将多个 Include() 与嵌套 Select() 一起使用时出现 EntityCommandExecutionException

Posted

技术标签:

【中文标题】将多个 Include() 与嵌套 Select() 一起使用时出现 EntityCommandExecutionException【英文标题】:EntityCommandExecutionException when using multiple Include() with nested Select() 【发布时间】:2018-09-30 17:23:31 【问题描述】:

我在 mysql 中使用实体框架。假设我有以下实体:

Country State City Car Building

要急切地包含一直到Cars,我可以使用以下内容:

context.Countries.
    Include(c => c.States.Select(s => s.Cities.Select(ci => ci.Cars))).ToList();

同样,要包含一直到Buildings,我可以使用:

context.Countries.
    Include(c => c.States.Select(s => s.Cities.Select(ci => ci.Buildings))).ToList();

它们都工作得很好。现在,我想将这两者结合起来,以便同时包含CarsBuildings,所以我执行以下操作:

context.Countries.
    Include(c => c.States.Select(s => s.Cities.Select(ci => ci.Cars))).
    Include(c => c.States.Select(s => s.Cities.Select(ci => ci.Buildings))).ToList();

但是每当我将两者结合在一起时--使用上面的代码--,它会抛出一个EntityCommandExecutionException 异常,并在内部异常中包含以下消息

"'字段列表'中的未知列'Apply1.Id'"

我花了两个小时试图找出查询出了什么问题,最后,我决定用 SQL Server 对其进行测试,结果它没有任何问题。

总结一下我的问题:

知道为什么这不适用于 MySQL 吗?查询本身有问题吗? 是否有任何解决方法/替代方法可以使用 MySQL 实现此目的?

请注意,这只发生在第三级(Select 的第二级),例如,以下操作就可以了:

context.Countries.
    Include(c => c.States.Select(s => s.Cities.Select(ci => ci.Cars))).
    Include(c => c.States.Select(s => s.Laws.Select(l => l.PrivacyLaws))).ToList();

如果相关,这里是完整的异常详细信息:

System.Data.Entity.Core.EntityCommandExecutionException was unhandled
  HResult=-2146232004
  Message=An error occurred while executing the command definition. See the inner exception for details.
  Source=EntityFramework
  StackTrace:
       at System.Data.Entity.Core.EntityClient.Internal.EntityCommandDefinition.ExecuteStoreCommands(EntityCommand entityCommand, CommandBehavior behavior)
       at System.Data.Entity.Core.Objects.Internal.ObjectQueryExecutionPlan.Execute[TResultType](ObjectContext context, ObjectParameterCollection parameterValues)
       at System.Data.Entity.Core.Objects.ObjectQuery`1.<>c__DisplayClass7.<GetResults>b__6()
       at System.Data.Entity.Core.Objects.ObjectContext.ExecuteInTransaction[T](Func`1 func, IDbExecutionStrategy executionStrategy, Boolean startLocalTransaction, Boolean releaseConnectionOnSuccess)
       at System.Data.Entity.Core.Objects.ObjectQuery`1.<>c__DisplayClass7.<GetResults>b__5()
       at System.Data.Entity.Infrastructure.DefaultExecutionStrategy.Execute[TResult](Func`1 operation)
       at System.Data.Entity.Core.Objects.ObjectQuery`1.GetResults(Nullable`1 forMergeOption)
       at System.Data.Entity.Core.Objects.ObjectQuery`1.<System.Collections.Generic.IEnumerable<T>.GetEnumerator>b__0()
       at System.Data.Entity.Internal.LazyEnumerator`1.MoveNext()
       at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
       at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
       at ConsoleApplication1.Program.Main(String[] args) in E:\Test\tmpEF\tmpEF\Program.cs:line 15
       at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
       at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
       at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()
  InnerException: 
       ErrorCode=-2147467259
       HResult=-2147467259
       Message=Unknown column 'Apply1.Id' in 'field list'
       Number=1054
       Source=MySql.Data
       StackTrace:
            at MySql.Data.MySqlClient.MySqlStream.ReadPacket()
            at MySql.Data.MySqlClient.NativeDriver.GetResult(Int32& affectedRow, Int64& insertedId)
            at MySql.Data.MySqlClient.Driver.GetResult(Int32 statementId, Int32& affectedRows, Int64& insertedId)
            at MySql.Data.MySqlClient.Driver.NextResult(Int32 statementId, Boolean force)
            at MySql.Data.MySqlClient.MySqlDataReader.NextResult()
            at MySql.Data.MySqlClient.MySqlCommand.ExecuteReader(CommandBehavior behavior)
            at MySql.Data.Entity.EFMySqlCommand.ExecuteDbDataReader(CommandBehavior behavior)
            at System.Data.Common.DbCommand.ExecuteReader(CommandBehavior behavior)
            at System.Data.Entity.Infrastructure.Interception.DbCommandDispatcher.<Reader>b__c(DbCommand t, DbCommandInterceptionContext`1 c)
            at System.Data.Entity.Infrastructure.Interception.InternalDispatcher`1.Dispatch[TTarget,TInterceptionContext,TResult](TTarget target, Func`3 operation, TInterceptionContext interceptionContext, Action`3 executing, Action`3 executed)
            at System.Data.Entity.Infrastructure.Interception.DbCommandDispatcher.Reader(DbCommand command, DbCommandInterceptionContext interceptionContext)
            at System.Data.Entity.Internal.InterceptableDbCommand.ExecuteDbDataReader(CommandBehavior behavior)
            at System.Data.Common.DbCommand.ExecuteReader(CommandBehavior behavior)
            at System.Data.Entity.Core.EntityClient.Internal.EntityCommandDefinition.ExecuteStoreCommands(EntityCommand entityCommand, CommandBehavior behavior)
       InnerException: 

【问题讨论】:

(1) 您的查询没有问题 (2) 当然这是 MySQL 提供程序错误。报告为#78798,似乎没有人关心复制和修复它(3)解决方法......好吧,祝你好运。 @IvanStoev 谢谢你找到这个。我只是按照他们的要求为他们提供了一个完整的可重复测试用例。希望尽快解决。 为什么不通过 ThenInclude() 函数尝试使用 EF Core 进行多级包含。看看这个entityframework.net/include-multiple-levels 【参考方案1】:

正如@IvanStoev 指出的那样,这已经是Reported Bug,但更好的问题是为什么您调用产生笛卡尔产生的查询。包含来自实体框架的多个数据集通常不是一个好主意。即

context.Countries.
    Include(c => c.States.Select(s => s.Cities.Select(ci => ci.Cars))).
    Include(c => c.States.Select(s => s.Cities.Select(ci => ci.Buildings))).ToList();

此查询将拉回其中的数据集,对于每 1 个建筑物,您拥有所有可能的汽车并包含城市信息。你在极大地浪费资源。相反,您应该单独加载集合,这将避免错误。并以最小的开销加载您的相关实体。最好你应该调用它,它也可以作为一种解决方法:

//You probably want to filter to the countries that have states
var countriesQuery = context.Countries.AsQueryable();
var statesQuery = countriesQuery.SelectMany(x => x.States);
statesQuery.Load();

var cityQuery = statesQuery.SelectMany(x => x.Cities);
cityQuery.Load();
cityQuery.SelectMany(x => x.Cars).Load();
cityQuery.SelectMany(x => x.Buildings).Load();
return countriesQuery.ToArray()

您可以决定加载包含国家/地区的州,但您不应该嵌套多对多,因为它可以增长幅度

【讨论】:

哇,这很有趣,我不知道Load 方法。它确实有效,但我仍然很难理解与使用IncludeSelect 相比,它如何使用更少的资源。例如,我仍然可以拨打returntedCountries.First().States.First().Cities.First().Cars.First().Id,对吗?它有什么区别?能否请您详细说明这部分。 没关系,我现在明白了。你的解释和this question都帮助我理解了。谢谢一百万:) @AhmedAbdelhameed 很高兴能为您提供帮助,如果您有任何其他问题,请告诉我

以上是关于将多个 Include() 与嵌套 Select() 一起使用时出现 EntityCommandExecutionException的主要内容,如果未能解决你的问题,请参考以下文章

EF LINQ 包括多个和嵌套的实体

压缩多个嵌套的select语句

具有多个嵌套 SELECT 的 MySQL INSERT

在 PHP 中使用多个条件访问嵌套的 MySQL Select。

elasticsearch aggs 嵌套查询 多个select 统计/聚合部分查询结果

如何将多个嵌套括号与指数一起使用?