2

我在我的项目中使用 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 有什么问题还是我错过了配置中的某些内容?

4

3 回答 3

4

默认情况下,EF 会跟踪您对其运行查询的所有实体。

当你第一次运行它时,轨道改变机制就会启动......这就是为什么它需要更长的时间。

您可以避免这种情况,尤其是.AsNoTracking()在编写查询时使用 检索集合时。

看一看:

var items = DbContext.MyDbSet
    .Include(SecondObject)
    .AsNoTracking()
    .ToList();
于 2018-06-18T16:44:50.947 回答
1

EF 核心需要使用反射编译 LINQ 查询,因此第一次查询总是很慢。这里已经有一个 GitHub 问题

于 2018-12-10T22:31:44.220 回答
0

我有一个简单的想法,可以借助存储过程和 AutoMapper 来解决这个问题。

创建一个存储过程来返回您想要的所有列,无论它们是否来自不同的表。一旦从存储过程中接收到数据并且您已在模型类之一中接收到对象,您就可以使用 AutoMapper 仅将相关属性映射到其他类。请注意,我没有给你一个如何使用存储过程的教程。我给你一个例子可以更好地解释:

  1. 创建了一个存储过程,该过程返回三个名为 A、B 和 C 的表的结果。

  2. SP_Result.cs对应于创建的存储过程创建一个名为的模型类,以映射接收到的存储过程对象(在 EF Core 中使用存储过程时需要这样做)

  3. 'ViewModels' 的创建具有与从每个表 A、B 和 C 返回相同的属性。

  4. 此后,将为 SP_Result 创建具有 A 类、B 类和 C 类 ViewModel 的映射配置。例如CreateMap<SP_Result, ViewModel_A>(); CreateMap<SP_Result, ViewModel_B>();。我想,你会有一个可以用来代替 ViewModel 的请求和响应对象。AS使用关键字在存储过程中相应地命名属性。例如Select std_Name AS 'Name'

此映射会将各个属性映射到每个类。AutoMapper 忽略映射配置中提到的任何一个类中都不存在的属性。

如果您选择一个对象列表,其中每个对象都有自己的对象列表,则此方案通常会在 EF 中创建 N + 1 个查询。事实上,如果您尝试使用存储过程来实现这一点,您将不得不创建多个查询或多次运行存储过程(可能是在一个循环中),否则您最终会收到笛卡尔积。

于 2020-05-14T11:06:08.653 回答