我有以下疑问。在代码中它是 Signup.Effort.Parent
var user = await context.AppUsers
.Include(user => user.Following!)
.ThenInclude(org => org.News)
.Include(user => user.Interests)
.Include(user => user.Signups!)
.ThenInclude(signup => signup.Effort)
.ThenInclude(effort => effort.Parent)
.FirstOrDefaultAsync(user => user.Id == _combinedUser.AppUser.Id);
如果我删除
ThenInclude(effort => effort.Parent)
那么一切都会正常运行。如果我将其保留,则会引发以下异常:
Microsoft.EntityFrameworkCore.Query: Warning: Compiling a query which loads related collections for more than one collection navigation, either via 'Include' or through projection, but no 'QuerySplittingBehavior' has been configured. By default, Entity Framework will use 'QuerySplittingBehavior.SingleQuery', which can potentially result in slow query performance. See https://go.microsoft.com/fwlink/?linkid=2134277 for more information. To identify the query that's triggering this warning call 'ConfigureWarnings(w => w.Throw(RelationalEventId.MultipleCollectionIncludeWarning))'.
The thread 0x14d8 has exited with code 0 (0x0).
'LouisHowe.web.exe' (CoreCLR: clrhost): Loaded 'C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App\7.0.10\Microsoft.AspNetCore.Components.Forms.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'LouisHowe.web.exe' (CoreCLR: clrhost): Loaded 'C:\Program Files\dotnet\shared\Microsoft.NETCore.App\7.0.10\System.Runtime.Serialization.Formatters.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'LouisHowe.web.exe' (CoreCLR: clrhost): Loaded 'C:\git\LouisHowe\LouisHowe.web\bin\Debug\net7.0\DevExtreme.AspNet.Data.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'LouisHowe.web.exe' (CoreCLR: clrhost): Loaded 'C:\Program Files\dotnet\shared\Microsoft.NETCore.App\7.0.10\Microsoft.CSharp.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
'LouisHowe.web.exe' (CoreCLR: clrhost): Loaded 'C:\Program Files\Microsoft Visual Studio\2022\Professional\Common7\IDE\PrivateAssemblies\Runtime\Microsoft.VisualStudio.Debugger.Runtime.NetCoreApp.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
Exception thrown: 'System.InvalidOperationException' in Microsoft.EntityFrameworkCore.dll
Exception thrown: 'System.InvalidOperationException' in System.Private.CoreLib.dll
Exception thrown: 'System.InvalidOperationException' in System.Private.CoreLib.dll
Exception thrown: 'System.InvalidOperationException' in LouisHowe.web.dll
'LouisHowe.web.exe' (CoreCLR: clrhost): Loaded 'C:\Program Files\dotnet\shared\Microsoft.NETCore.App\7.0.10\System.Reflection.Metadata.dll'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
Microsoft.AspNetCore.Components.Web.ErrorBoundary: Warning: Unhandled exception rendering component: The expression 'effort.Parent' is invalid inside an 'Include' operation, since it does not represent a property access: 't => t.MyProperty'. To target navigations declared on derived types, use casting ('t => ((Derived)t).MyProperty') or the 'as' operator ('t => (t as Derived).MyProperty'). Collection navigation access can be filtered by composing Where, OrderBy(Descending), ThenBy(Descending), Skip or Take operations. For more information on including related data, see http://go.microsoft.com/fwlink/?LinkID=746393.
System.InvalidOperationException: The expression 'effort.Parent' is invalid inside an 'Include' operation, since it does not represent a property access: 't => t.MyProperty'. To target navigations declared on derived types, use casting ('t => ((Derived)t).MyProperty') or the 'as' operator ('t => (t as Derived).MyProperty'). Collection navigation access can be filtered by composing Where, OrderBy(Descending), ThenBy(Descending), Skip or Take operations. For more information on including related data, see http://go.microsoft.com/fwlink/?LinkID=746393.
at Microsoft.EntityFrameworkCore.Query.Internal.NavigationExpandingExpressionVisitor.PopulateIncludeTree(IncludeTreeNode includeTreeNode, Expression expression, Boolean setLoaded)
at Microsoft.EntityFrameworkCore.Query.Internal.NavigationExpandingExpressionVisitor.ProcessInclude(NavigationExpansionExpression source, Expression expression, Boolean thenInclude, Boolean setLoaded)
at Microsoft.EntityFrameworkCore.Query.Internal.NavigationExpandingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
at Microsoft.EntityFrameworkCore.Query.Internal.NavigationExpandingExpressionVisitor.VisitMethodCall(MethodCallExpression methodCallExpression)
at Microsoft.EntityFrameworkCore.Query.Internal.NavigationExpandingExpressionVisitor.Expand(Expression query)
at Microsoft.EntityFrameworkCore.Query.QueryTranslationPreprocessor.Process(Expression query)
at Microsoft.EntityFrameworkCore.Query.QueryCompilationContext.CreateQueryExecutor[TResult](Expression query)
at Microsoft.EntityFrameworkCore.Storage.Database.CompileQuery[TResult](Expression query, Boolean async)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.CompileQueryCore[TResult](IDatabase database, Expression query, IModel model, Boolean async)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.<>c__DisplayClass12_0`1.<ExecuteAsync>b__0()
at 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.EntityFrameworkQueryableExtensions.ExecuteAsync[TSource,TResult](MethodInfo operatorMethodInfo, IQueryable`1 source, Expression expression, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ExecuteAsync[TSource,TResult](MethodInfo operatorMethodInfo, IQueryable`1 source, LambdaExpression expression, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.FirstOrDefaultAsync[TSource](IQueryable`1 source, Expression`1 predicate, CancellationToken cancellationToken)
at LouisHowe.web.Pages.User.Dashboard.ReadEventsFromDb() in C:\git\LouisHowe\LouisHowe.web\Pages\User\Dashboard.razor.cs:line 118
at LouisHowe.web.Pages.User.Dashboard.ReadEventsFromDb() in C:\git\LouisHowe\LouisHowe.web\Pages\User\Dashboard.razor.cs:line 169
at LouisHowe.web.Pages.User.Dashboard.OnInitializedAsync() in C:\git\LouisHowe\LouisHowe.web\Pages\User\Dashboard.razor.cs:line 104
at Microsoft.AspNetCore.Components.ComponentBase.RunInitAndSetParametersAsync()
at Microsoft.AspNetCore.Components.RenderTree.Renderer.GetErrorHandledTask(Task taskToHandle, ComponentState owningComponentState)
LouisHowe.web.Pages.User.Dashboard: Error: Error: 50666d4d-59aa-4a75-bc84-7d6c11445c12
各班级相关部分:
public class Signup : IAuditTrail, IPrimaryEntities, IDisableable
{
public Effort Effort { get; set; }
public int EffortId { get; private set; }
}
public abstract class Effort : IAuditTrail, IPrimaryEntities, IDisableable
{
public Organization Parent { get; set; }
public int ParentId { get; private set; }
public List<Signup>? Signups { get; set; }
}
public class Event : Effort
{
}
public class Organization : IPrimaryEntities, IAuditTrail, IDisableable
{
public List<Event>? Events { get; private set; }
}
知道为什么它不喜欢这个吗?
该错误可能与您从“努力”转到“组织”有关,但“组织”有一个扩展“努力”的事件列表,而 EF 很可能不太喜欢这样。如果您希望组织在“事件”与其他类型之间拆分“工作量”的引用,我建议使用映射供 EF 使用的“工作量”列表,然后使用可以将工作量拆分为的未映射子列表事件等的集合。这些子列表不能在 Linq 查询中使用,因为您必须转到基础工作。
public class Organization : IPrimaryEntities, IAuditTrail, IDisableable
{
public List<Effort> Efforts { get; private set; } = new();
[NotMapped]
public IEnumerable<Event> Events => Efforts.OfType<Event>();
}
总的来说,对于参与聚合根的实体,如果可以避免的话,我通常不建议使用继承。有时继承的理由仅仅是多个不同的类/表似乎共享相同的字段,只有当这些类在引用时可以相互互换时才应该考虑。 IE。组织与事件或任何其他子类相关联只是一个事实,而不是期望只有某些子类参与该关系。
或者,如果组织仅适用于活动:
public abstract class Effort : IAuditTrail, IPrimaryEntities, IDisableable
{
public List<Signup>? Signups { get; set; }
}
public class Event : Effort
{
public int ParentId { get; private set; }
public Organization Parent { get; set; }
}
public class Organization : IPrimaryEntities, IAuditTrail, IDisableable
{
public List<Event> Events { get; private set; } = new();
}
这种形式的继承最好通过 EF/DB 中的 Table-per-Type 或 Table-per-Concrete 继承支持来实现,而不是 Table-per-Hierarchy。在这种情况下,继承更多地表达了实体具有哪些公共字段,而不是它们在数据关系中的角色,因为基类/接口可能表达公共 Id 列、IsActive 列等。实体共享。
关于
AsSplitQuery
的另一个警告是 EF Core 的一项新功能,它对导致大量联接的场景发出警告,这些联接可能会根据结果查询将返回的行数和列数产生重要的笛卡尔积。在这些情况下,新的 AsSplitQuery
可以分解表达式以跨相关表运行单独的查询,从而返回较小的总数据集。根据 a、b、c 和 d 表的组合返回的列数和行数,联接会产生 a x b x c x d 场景。就返回的数据量而言,AsSplitQuery
可以将其减少为更多的 a + b + c + d。