c# - 使用 join 进行预加载

标签 c# sql-server entity-framework lazy-loading

我有一个连接两个表的查询,这两个表在 Entity Framework 中没有定义的关系,并且连接的表具有到第三个表的一对多导航属性。

msg 和 job 之间存在一对多关系,但没有外键,也没有在 .EDMX 中定义关联。

job和lock是一对多的关系,在.EDMX中定义了一个关联,所以job有一个job.locks导航属性m,lock有一个lock.job导航属性。

我的原始查询:

var msgsAndJobs = (
    from m in dbContext.msgs
    join j in dbContext.jobs
        on new { jobid = m.jobid, priority = m.priority }
        equals new { jobid = j.jobid, priority = j.priority }
    where m.msgtype == "EMERGENCY"
    orderby new { m.recvdt }
    select new { m, j }
    );

我发现 EF 正在为联接生成一个查询,然后执行第二个查询以填充联接返回的每条记录的导航属性。

Microsoft 的文档解释了这个问题:https://msdn.microsoft.com/en-us/data/jj574232.aspx

所以我认为我可以使用 .Include() 子句来急切加载所涉及的记录。但它似乎不起作用:

我的新查询:

var msgsAndJobs = (
    from m in dbContext.msgs
    join j in dbContext.jobs.Include("locks")
        on new { jobid = m.jobid, priority = m.priority }
        equals new { jobid = j.jobid, priority = j.priority }
    where m.msgtype == "EMERGENCY"
    orderby new { m.recvdt }
    select new { m, j }
    );

而且它仍在为每个作业锁生成一个查询。

知道我做错了什么吗?

最佳答案

这就是 Include 的问题。让它失效太容易了,而且它为什么不起作用并不总是很清楚。破坏 Include 的一件事是 changing the shape of the query .另一个是 projecting to a non-entity type or an anonymous type .

这似乎使得预测 Include 何时起作用和不起作用变得异常困难,但有一个简单的技巧:Include 总是起作用,如果你在查询结束时应用它。

如果你不能在那里应用它,它无论如何都不会有效。

考虑到这一点,如果我们查看您的案例,就会很清楚为什么 Include 不起作用。你做不到

(... select new { m, j }).Include("locks"); // Runtime error

因为 locks 显然不是匿名类型的导航属性。如果您使用 lambda 版本,则更明显:

(... select new { m, j }).Include(x => x.locks); // Doesn't compile

所以你的Include是无效的,locks是按需加载的。

幸运的是,由于关系修复,EF 可以通过实体的导航属性将上下文中的实体编织在一起。将您的查询更改为:

var msgsAndJobs = (
    from m in dbContext.msgs
    join j in dbContext.jobs
        on new { jobid = m.jobid, priority = m.priority }
        equals new { jobid = j.jobid, priority = j.priority }
    where m.msgtype == "EMERGENCY"
    orderby new { m.recvdt }
    select new { m, j, j.locks }
    ).AsEnumerable()
    .Select(x => new { x.m, x.j });

如果您执行此查询,.AsEnumerable() 会将结果加载到上下文中,之后您可以选择您最初想要的结果。现在您会注意到 EF 已填充所有 job.locks 集合。

但有一件重要的事情:您必须禁用延迟加载,否则处理 job.locks 集合仍会触发延迟加载。这是因为,即使集合已填充,它也未在内部标记为 Loaded

关于c# - 使用 join 进行预加载,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32955623/

相关文章:

sql-server - NULLIF 和 0 转换的 TSQL 问题

基于尚未匹配的第一个匹配的出现顺序的 SQL 连接

sql - 使用关系表触发器删除值与

entity-framework - 同一数据库的多个 Entity Framework

c# - 在不同 session 之间共享一级缓存?

c# - ASP.NET MVC 单点登录和角色

c# - 在 SQL 数据库中存储加密的信用卡号

c# - EF Code First,由于 'Can' t Insert duplicate key in object' for twice separated navigation property,通用更新失败

c# - Linq/ Entity Framework 中的对象和上下文有什么区别

c# - 改进/修复 C 样式 block 注释的正则表达式