合并两个IQueryable结果返回错误

时间:2019-06-05 11:50:37

标签: c# performance entity-framework linq iqueryable

我有4个使用EntityFramework的查询,它们在拖车/卡车/汽车/工厂上运行,由于结果量大,我需要先将它们连接在一起再执行。

所有4个实体都继承自Asset类型。

这是我要执行的代码以及各种不同的代码:

 var truckModels = await truckService.GetAll();
 var trailerModels = await trailerService.GetAll();
 var companyCarModels = await companyCarService.GetAll();
 var plantModels = await plantService.GetAll();

没有任何内容:

 assetModels = truckModels.Cast<Asset>()
 .Union(trailerModels)
 .Union(companyCarModels)
 .Union(plantModels);

使用Cast:

 assetModels = truckModels.Cast<Asset>()
 .Union(trailerModels.Cast<Asset>())
 .Union(companyCarModels.Cast<Asset>())
 .Union(plantModels.Cast<Asset>());

具有AsEnumerable:

 assetModels = truckModels.Cast<Asset>()
 .Union(trailerModels.AsEnumerable())
 .Union(companyCarModels.AsEnumerable())
 .Union(plantModels.AsEnumerable());

使用Cast和AsEnumerable:

 assetModels = truckModels.Cast<Asset>()
 .Union(trailerModels.Cast<Asset>().AsEnumerable())
 .Union(companyCarModels.Cast<Asset>().AsEnumerable())
 .Union(plantModels.Cast<Asset>().AsEnumerable());

但是我在所有版本上都遇到以下错误:

  

“此方法支持LINQ to Entities基础结构,不能直接在您的代码中使用。”

at System.Data.Entity.Core.Objects.ObjectQuery`1.MergeAs(MergeOption mergeOption)
at lambda_method(Closure )
at System.Linq.EnumerableExecutor`1.Execute()
at System.Linq.EnumerableQuery`1.System.Linq.IQueryProvider.Execute[S](Expression expression)
at Kendo.Mvc.Extensions.QueryableExtensions.Count(IQueryable source)
at Kendo.Mvc.Extensions.QueryableExtensions.CreateDataSourceResult[TModel,TResult](IQueryable queryable, DataSourceRequest request, ModelStateDictionary modelState, Func`2 selector)
at Kendo.Mvc.Extensions.QueryableExtensions.<>c__DisplayClass10.<ToDataSourceResultAsync>b__f()
at System.Threading.Tasks.Task`1.InnerInvoke()
at System.Threading.Tasks.Task.Execute()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at Viper.Web.Areas.Assets.Controllers.AllController.<GetAssets>d__7.MoveNext() in C:\Repositories\ViperRepo\Viper\Viper.Web\Areas\Assets\Controllers\AllController.cs:line 90

有什么想法吗?我以为您可以合并IQueryable ...

1 个答案:

答案 0 :(得分:1)

什么是.GetAll()。在我看来,您有一个意外的Closure,无法将其转换为EntityFramework操作。

EntityFramework不知道TruckServiceTrailerService是什么。

如果分解Linq表达式,您会发现您有一个类似

的元素
Expression.Lambda(
       methodinfo(TruckService.GetAll)
       Expression.Parameter(typeof(TruckService))
)

实体框架不知道应该将其简化为

Expression.Lambda(
       Expression.Call(
            methodInfo(DbContext.DbSet<Truck>),
            Expression.Parameter(typeof(AssetDbContext))
       )
)

您在这里有一些选择。

  1. 直接使用DbContext实例
  2. 构造一个ExpressionVisitor来重写表达式树以进行上述转换

但是,每个AssetService中的DbContext显然不是相同的DbContext,这是它参与同一查询所必需的。