如何使用多个包含因子分解Linq请求?

时间:2017-03-09 14:27:53

标签: c# entity-framework linq entity

我想简化包含多个包含的linq查询。

我的模型很简单:网站链接到一个合同,链接到一个客户端。在那个客户端,我需要一个单一的请求电话,邮件和敬意(appelRef)。

我想要一个请求,因为请求背后是由实体框架转换为SQL Server请求。

这是linq请求:

var search =
from IMT.Site s in imtContext.IMTObjects.OfType<IMT.Site>()
.Include(
s => s.LienContratSiteRef
    .Select(l => l.Contrat)
        .Select(c => c.LienContratClientRef
            .Select(l => l.Client)
                .Select(cl => cl.Telephones ) ) )

.Include(s => s.LienContratSiteRef
    .Select(l => l.Contrat)
        .Select(c => c.LienContratClientRef
            .Select(l => l.Client)
                .Select(cl => cl.Mails ) ) )

.Include(s => s.LienContratSiteRef
    .Select(l => l.Contrat)
        .Select(c => c.LienContratClientRef
            .Select(l => l.Client)
                .Select(cl => cl.AppelRef ) ) )

where s.Reference.ToString() == siteId
select s;

你可以注意到阻止

.Include(
s => s.LienContratSiteRef
    .Select(l => l.Contrat)
        .Select(c => c.LienContratClientRef
            .Select(l => l.Client)

..重复三次。是一种分解代码块的方法吗?

更新:有中间对象LienContratSiteRef和LienContratClientRef,关系为0 - *,因此LienContratSiteRef.Contrat和LienContratClientRef.Client都是集合。

我也尝试过:

.Include(
s => s.LienContratSiteRef
    .Select(l => l.Contrat)
        .Select(c => c.LienContratClientRef
            .Select(l => l.Client)
                .Select(cl => new { Tels = cl.Telephones, Mail = cl.Mails, Appel = cl.AppelRef} ) ) )

但它会导致运行时错误:

  

Include路径表达式必须引用导航属性   在类型上定义。

3 个答案:

答案 0 :(得分:0)

基于字符串的链接

Include() method supports a dot-delimited string parameter可以用来拉下完整的对象图,而不是进行多个链式选择调用:

.Include("LienContratSiteRif.Contrat.LienContratClientRef.Client")

从那里开始,如果你想要包含多个附加属性,我相信你可以为这些子属性添加另一个属性:

.Include("LienContratSiteRif.Contrat.LienContratClientRef.Client, Client.Telephones, ...")

基于Lambda的链接

您应该能够通过将基于lambda的包含链接到单个Include()调用中来完成类似的操作:

.Include(c => LienContratSiteRif.Contrat.LienContratClientRef.Client)

答案 1 :(得分:0)

包含中的s => ...可以重构为委托,然后仅.Include委托多次。

看起来签名是Func<Site, IEnumerable<Client>>

E.g。

static IEnumerable<Client> Foo(Site site) => site.LienContratSiteRef
    .Select(l => l.Contrat)
        .Select(c => c.LienContratClientRef
            .Select(l => l.Client)

答案 2 :(得分:0)

您似乎正在尝试进行实体框架投影!

项目允许您仅选择要返回的属性。 (就像SQL Select一样)

要使用投影,您的代码大致应如下所示:

var search = imtContext.IMTObjects.OfType<IMT.Site>()
.Where(s => s.Reference.ToString() == siteId)
.Select(s => new {
     Telephones = s.LienContratSiteRef.Contrat.Select(c =>  c.LienContratClientRef.Client.Select(cli => cli.Telephones), 
     Mails = s.LienContratSiteRef.Contrat.Select(c =>  c.LienContratClientRef.Client.Select(cli => cli.Mails), 
     AppelRef = s.LienContratSiteRef.Contrat.Select(c =>  c.LienContratClientRef.Client.Select(cli => cli.AppelRef)     
}).ToList();

如果TelephonesMailsAppelRef也是集合,那么您可以在运行查询后在内存中聚集这些集合:

var telephones = search.SelectMany(x => x.Telephones).ToList();
var mails = search.SelectMany(x => x.Mails).ToList();
var appelRefs = search.SelectMany(x => x.AppelRef).ToList();