EFcore LazyLoading-在对子属性进行过滤时对数据库的请求

时间:2019-05-25 15:51:05

标签: c# ef-core-2.2

我正在使用延迟加载,并且担心性能。

假设我有一个对象A,其中包含对象B的列表。

我将使用延迟加载从数据库中检索对象A。这意味着如果我不访问它,将不会检索对象B的列表。

但是,如果我做这样的事情:

ObjectA.ObjectsB.Where(b => b.Id == 12);

它将查询所有对象B并对其进行过滤,还是仅查询表达式的结果?

4 个答案:

答案 0 :(得分:1)

如果您使用的是SQL Server,则可以使用SQL Server Profiler查看SQL正在执行的查询类型。

我做了以下查询:

        var context = new LabContextDb();
        var user = context.Users.FirstOrDefault(x => x.Id == 1);
        var roles = user.UserRoles.Where(x => x.UserId == 1).ToList();

我生成的SQL是:

SELECT TOP(1) [x].[Id] FROM [AbpUsers] AS [x] WHERE [x].[Id] = CAST(1 AS bigint)

exec sp_executesql N'SELECT [e].[Id], [e].[RoleId], [e].[UserId]
FROM [AbpUserRoles] AS [e]
WHERE [e].[UserId] = @__get_Item_0',N'@__get_Item_0 bigint',@__get_Item_0=1

但是,如果我做这样的事情:

var user = context.Users.FirstOrDefault(x => x.UserRoles.Any(y => y.Id == 1));

我的SQL将是这样的:

  SELECT TOP(1) [x].[Id]
  FROM [AbpUsers] AS [x]
  WHERE EXISTS (SELECT 1
  FROM [AbpUserRoles] AS [y]
  WHERE ([y].[Id] = CAST(1 AS bigint)) AND ([x].[Id] = [y].[UserId]))

SQL Server Profiler是查看幕后情况的好方法。另一个提示是使用.ToList(),而不是如果您需要遍历大列表,那么自从您使用Where条件返回IQueryable(...)以来,每次循环都不会执行您的语句。

答案 1 :(得分:0)

好吧,在阅读了Flavio Francisco的答案之后,我用SQL事件探查器对自己进行了测试。

var objectA = (await _repo.Object.FindByCondition(obj => obj.Id == 3)).FirstOrDefault();
var objectB = objectA.ObjectsB.Where(obj => obj.Id == 1);

在事件探查器中,它首先进行调用以获取对象A,然后请求所有对象B。

因此,不幸的是,过滤器是在代码级别发生的。

答案 2 :(得分:0)

也许它将为您工作。

var objectB = (from objA in _repo.Object join objB in ObjectsB 
               on objA.Id equals objB.ObjectAId
               where objA.Id == 3 && objB.Id == 1
               select u).ToList();

为避免调用所有对象B。

答案 3 :(得分:0)

实际上,您可以按照this文档中的说明进行操作,该文档与ef core的this文档相同:

dbContext.Entry(ObjectA)
    .Collection(b => b.ObjectsB)
    .Query()
    .Where(b => b.Id == 12)
    .Load();

然后使用Sql Profiler对其进行跟踪,并在数据库级别对其进行过滤。