我正试图让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);
事实:
希望我没有忘记任何事情,因为我创造了一个更轻松的场景,直到解决了这个问题:)
这是我的模型课
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
)时,每个项目都可以是SurveyGroupFieldText
或SurveyGroupFieldNumber
。
我正在尝试通过一个查询.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,Func1 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.IncludableQueryable2.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();
在一个查询中有什么方法可以做到吗?为什么只有两个查询有效?