在实体框架核心中包含摘要

时间:2020-03-08 20:36:04

标签: asp.net-web-api entity-framework-core abstract-class

我正试图让Entity Framework处理一些值,这些值可以是许多不同的类型,具体取决于数据库也处理的某些元数据。

我的示例有点过大,因为我只在Int和String之间更改了我的值,但这是为了简化示例以更好地了解我的需求。

我的OnModelCreating看起来像这样:

builder.Entity<Survey>().HasMany(c => c.SurveyGroups).WithOne(c => c.Survey);
builder.Entity<SurveyGroup>().HasOne(c => c.Survey).WithMany(c => c.SurveyGroups).HasForeignKey(c => c.SurveyId);
builder.Entity<SurveyGroup>().HasIndex(c => new { c.SurveyId, c.Order }).IsUnique();

builder.Entity<SurveyGroupField>().HasIndex(c => new { c.SurveyGroupId, c.Order }).IsUnique();

builder.Entity<SurveyGroupField>().HasOne(c => c.SurveyGroup).WithMany(c => c.SurveyGroupFields).HasForeignKey(c => c.SurveyGroupId);

builder.Entity<SurveyGroupFieldTextValue>().HasKey(c => new { c.Owner, c.SurveyGroupFieldTextId });
builder.Entity<SurveyGroupFieldTextValue>().HasIndex(c => new { c.Owner, c.SurveyGroupFieldTextId }).IsUnique();

builder.Entity<SurveyGroupFieldNumberValue>().HasKey(c => new { c.Owner, c.SurveyGroupFieldNumberId});
builder.Entity<SurveyGroupFieldNumberValue>().HasIndex(c => new { c.Owner, c.SurveyGroupFieldNumberId }).IsUnique();

builder.Entity<SurveyGroupFieldText>().HasMany(c => c.Values).WithOne(c => c.SurveyGroupFieldText).HasForeignKey(c => c.SurveyGroupFieldTextId);
builder.Entity<SurveyGroupFieldNumber>().HasMany(c => c.Values).WithOne(c => c.SurveyGroupFieldNumber).HasForeignKey(c => c.SurveyGroupFieldNumberId);

事实:

  • 一个调查可以有多个调查组
  • 一个调查组可以有多个调查场
  • Surveyfield是SurveyGroupFieldText和SurveyGroupFieldNumber之间的摘要
  • SurveyGroupFieldText具有一个称为“值”的属性,该属性是由不同用户在此字段中输入的文本值的集合。
  • SurveyGroupFieldNumber具有一个称为“值”的属性,该属性是由不同用户在此字段中输入的Number值的集合

希望我没有忘记任何事情,因为我创造了一个更轻松的场景,直到解决了这个问题:)

这是我的模型课

public class Survey
{
        public string Id { get; set; }
        public string Name { get; set; }
        public ICollection<SurveyGroup> SurveyGroups { get; set; }

        public Survey(string name)
        {
            Id = Guid.NewGuid().ToString();
            Name = name;
        }

        public Survey(string name, ICollection<SurveyGroup> surveyGroups) : this(name)
        {
            SurveyGroups = surveyGroups;
        }
}

public class SurveyGroup
{
        public string Id { get; set; }
        public int Order { get; set; } = 0;
        public string Name { get; set; }
        public Survey Survey { get; set; }
        public string SurveyId { get; set; }

        public ICollection<SurveyGroupField> SurveyGroupFields { get; set; }

        public SurveyGroup(int order, string name)
        {
            Id = Guid.NewGuid().ToString();
            Order = order;
            Name = name;
        }

        public SurveyGroup(int order, string name, ICollection<SurveyGroupField> surveyGroupFields) : this(order, name)
        {
            SurveyGroupFields = surveyGroupFields;
        }
}

public abstract class SurveyGroupField
{
        public string Id { get; set; }
        public int Order { get; set; } = 0;
        public string Name { get; set; }
        public string Description { get; set; }
        public SurveyGroup SurveyGroup { get; set; }
        public string SurveyGroupId { get; set; }
        public string Discriminator { get; set; }

        public SurveyGroupField(int order, string name, string description)
        {
            Id = Guid.NewGuid().ToString();
            Order = order;
            Name = name;
            Description = description;
        }
}

public class SurveyGroupFieldNumber : SurveyGroupField
{
        public SurveyGroupFieldNumber(int order, string name, string description) : base(order, name, description)
        {
        }

        public SurveyGroupFieldNumber(int order, string name, string description, ICollection<SurveyGroupFieldNumberValue> values) : this(order, name, description)
        {
            Values = values;
        }

        public SurveyGroupFieldNumber(int order, string name, string description, Func<SurveyGroupFieldNumber, ICollection<SurveyGroupFieldNumberValue>> func) : this(order, name, description)
        {
            Values = func.Invoke(this);
        }

        public ICollection<SurveyGroupFieldNumberValue> Values { get; set; }
}

public class SurveyGroupFieldNumberValue
{
        public string Owner { get; set; }
        public int Value { get; set; }
        public SurveyGroupFieldNumber SurveyGroupFieldNumber { get; set; }
        public string SurveyGroupFieldNumberId { get; set; }

        public SurveyGroupFieldNumberValue(string owner, int value)
        {
            Owner = owner;
            Value = value;
        }

        public SurveyGroupFieldNumberValue(string owner, int value, SurveyGroupFieldNumber surveyGroupFieldNumber) : this(owner, value)
        {
            SurveyGroupFieldNumber = surveyGroupFieldNumber;
            SurveyGroupFieldNumberId = surveyGroupFieldNumber?.Id;
        }
}

public class SurveyGroupFieldText : SurveyGroupField
{
        public SurveyGroupFieldText(int order, string name, string description) : base(order, name, description)
        {
        }

        public SurveyGroupFieldText(int order, string name, string description, ICollection<SurveyGroupFieldTextValue> values) : this(order, name, description)
        {
            Values = values;
        }

        public SurveyGroupFieldText(int order, string name, string description, Func<SurveyGroupFieldText, ICollection<SurveyGroupFieldTextValue>> func) : this(order, name, description)
        {
            Values = func.Invoke(this);
        }

        public ICollection<SurveyGroupFieldTextValue> Values { get; set; }
}

public class SurveyGroupFieldTextValue
{
        public string Owner { get; set; }
        public string Value { get; set; }
        public SurveyGroupFieldText SurveyGroupFieldText { get; set; }
        public string SurveyGroupFieldTextId { get; set; }

        public SurveyGroupFieldTextValue(string owner, string value)
        {
            Owner = owner;
            Value = value;
        }

        public SurveyGroupFieldTextValue(string owner, string value, SurveyGroupFieldText surveyGroupFieldText) : this(owner, value)
        {
            SurveyGroupFieldText = surveyGroupFieldText;
            SurveyGroupFieldTextId = surveyGroupFieldText?.Id;
        }
}

我的问题是,当我尝试包括抽象表(SurveyGroupField)时,每个项目都可以是SurveyGroupFieldTextSurveyGroupFieldNumber

我正在尝试通过一个查询.Include对它们进行搜索,但是似乎不起作用。

_context.Entry(survey)
                .Collection(i => i.SurveyGroups)
                .Query()
                .Include(c => c.SurveyGroupFields);
            await inc.ThenInclude(c => (c as SurveyGroupFieldNumber).Values).ThenInclude(c => (c as SurveyGroupFieldText).Values).LoadAsync();

然后我得到这个异常

System.InvalidOperationException:无效的包含。

在Microsoft.EntityFrameworkCore.Query.Internal.NavigationExpandingExpressionVisitor.PopulateIncludeTree(IncludeTreeNode includeTreeNode,Expression expression)中的

在Microsoft.EntityFrameworkCore.Query.Internal.NavigationExpandingExpressionVisitor.ProcessInclude(NavigationExpansionExpression源,表达式表达式,布尔值thenInclude) 在Microsoft.EntityFrameworkCore.Query.Internal.NavigationExpandingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression) 在System.Linq.Expressions.MethodCallExpression.Accept(ExpressionVisitor访问者) 在System.Linq.Expressions.ExpressionVisitor.Visit(Expression节点) 在Microsoft.EntityFrameworkCore.Query.Internal.NavigationExpandingExpressionVisitor.Expand(表达式查询) 在Microsoft.EntityFrameworkCore.Query.QueryTranslationPreprocessor.Process(表达式查询) 在Microsoft.EntityFrameworkCore.Query.QueryCompilationContext.CreateQueryExecutor [TResult](表达式查询) 在Microsoft.EntityFrameworkCore.Storage.Database.CompileQuery [TResult](表达式查询,布尔异步) 在Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.CompileQueryCore [TResult](IDatabase数据库,表达式查询,IModel模型,布尔异步) 在Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler。<> c__DisplayClass12_0 1.<ExecuteAsync>b__0() at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQueryCore[TFunc](Object cacheKey, Func 1编译器处) 在Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQuery [TResult](Object cacheKey,Func 1 compiler) at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.ExecuteAsync[TResult](Expression query, CancellationToken cancellationToken) at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.ExecuteAsync[TResult](Expression expression, CancellationToken cancellationToken) at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable 1.GetAsyncEnumerator(CancellationToken cancelleToken) Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.IncludableQueryable 2.GetAsyncEnumerator(CancellationToken cancellationToken) at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.LoadAsync[TSource](IQueryable 1的来源,CancellationToken cancelToken) 在D:\ Codes \ Development \ IPN.Survey \ ApiService \ Controllers \ SurveysController.cs:line 46中的ApiService.Controllers.SurveysController.GetSurvey(String id) 在lambda_method(Closure,Object) 在Microsoft.Extensions.Internal.ObjectMethodExecutorAwaitable.Awaiter.GetResult() 在Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.AwaitableObjectResultExecutor.Execute(IActionResultTypeMapper映射器,ObjectMethodExecutor执行器,对象控制器,Object []参数) 在Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.g__Awaited | 12_0(ControllerActionInvoker调用程序,ValueTask`1 actionResultValueTask) 在Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.g__Awaited | 10_0(ControllerActionInvoker调用程序,Task lastTask,Next状态,Scope作用域,对象状态,布尔值isCompleted) 在Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed上下文) 在Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(状态和下一个,范围和范围,对象和状态,布尔值和isCompleted)处 在Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync() ---从之前引发异常的位置开始的堆栈结束跟踪--- 在Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited | 19_0(ResourceInvoker调用程序,Task lastTask,Next状态,Scope作用域,对象状态,布尔值isCompleted) 在Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited | 17_0(ResourceInvoker调用程序,任务任务,IDisposable范围) 在Microsoft.AspNetCore.Routing.EndpointMiddleware.g__AwaitRequestTask | 6_0(端点端点,任务requestTask,ILogger记录器) 在Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext上下文) 在Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext上下文)

但是,如果我对2个查询执行此操作,它将起作用。

    var inc = _context.Entry(survey)
        .Collection(i => i.SurveyGroups)
        .Query()
        .Include(c => c.SurveyGroupFields);
    await inc.ThenInclude(c => (c as SurveyGroupFieldNumber).Values).LoadAsync();
    await inc.ThenInclude(c => (c as SurveyGroupFieldText).Values).LoadAsync();

在一个查询中有什么方法可以做到吗?为什么只有两个查询有效?

0 个答案:

没有答案