我在我的项目中使用EF core 2作为ORM。 我在执行此查询时遇到了这个问题:
var query = (from droitsGeo in _entities.DroitsGeos
join building in _entities.Batiments
on droitsGeo.IdPerimetre equals building.IdBatiment
where droitsGeo.IdUtilisateur == idUser &&
droitsGeo.IdClient == idClient &&
building.Valide == true &&
droitsGeo.IdNiveauPerimetre == geographicalLevel
orderby sort ascending
select new GeographicalModel
{
Id = building.IdBatiment,
IdParent = building.IdEtablissement,
Label = building.LibBatiment,
});
第一次执行大约需要5秒,第二次不到一秒,如下所示:
首次执行查询:
时间流逝EF:00:00:04.8562419
首次执行查询后:
经过时间EF:00:00:00.5496862
经过时间EF:00:00:00.6658079
经过时间EF:00:00:00.6176030
我使用存储过程得到相同的结果。
当我在SQL Server中执行EF生成的sql查询时,结果会在不到一秒的时间内返回。
EF Core 2出了什么问题,或者我在配置中遗漏了什么?
答案 0 :(得分:3)
默认情况下,EF会跟踪您运行查询的所有实体。
第一次运行时,跟踪更改机制会启动......这就是为什么需要更长的时间。
您可以避免这种情况,尤其是在撰写查询时使用.AsNoTracking()
检索集合时。
看看:
var items = DbContext.MyDbSet
.Include(SecondObject)
.AsNoTracking()
.ToList();
答案 1 :(得分:1)
EF内核需要使用反射来编译LINQ查询,因此第一次查询总是很慢。 GitHub问题here
答案 2 :(得分:0)
我有一个简单的想法,可以借助存储过程以及此后的AutoMapper解决此问题。
创建一个存储过程,以返回所需的所有列,无论它们来自不同的表。一旦从存储过程中接收到数据,并且您已经在Model类之一中接收到对象,则可以使用AutoMapper将相关属性仅映射到其他类。请注意,我没有为您提供有关如何使用存储过程的教程。我给你一个例子,可能会更好地解释:
创建了一个存储过程,该存储过程从名为A,B和C的三个表中返回结果。
对应于已创建的存储过程,创建了一个名为SP_Result.cs
的模型类,以映射存储过程的接收对象(在EF Core中使用存储过程时需要)
创建的“ ViewModels”具有与从每个表A,B和C返回的属性相同的属性。
此后,将使用A,B和C类的ViewModel为SP_Result创建映射配置。 CreateMap<SP_Result, ViewModel_A>(); CreateMap<SP_Result, ViewModel_B>();
。我想,您将拥有一个可以代替ViewModels使用的请求和响应对象。使用AS
关键字在存储过程中相应地命名属性。例如Select std_Name AS 'Name'
此映射会将各个属性映射到每个类。 AutoMapper会忽略“映射配置”中提到的两个类都不存在的属性。
如果选择的对象列表中每个对象确实都有自己的对象列表,则此方案通常将在EF中创建N + 1个查询。实际上,如果尝试使用存储过程来实现此目的,则必须创建多个查询或多次运行该存储过程(可能是循环运行),否则最终将收到笛卡尔积。