2017-03-09 58 views
0

我想簡化一個包含多個包含的linq查詢。如何將包含多個Linq請求的因子分解?

我的模式很簡單:一個網站鏈接到一個合同,鏈接到一個客戶。在那個客戶端,我需要得到一個請求電話,郵件和敬語(appelRef)。

我想,因爲後面的請求是由實體框架轉換成SQL服務器請求一個請求。

這裏是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) 

..是重複三次。它是否可以將該代碼塊分解?

更新:有intermedray對象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}))) 

,但它導致了運行時錯誤:

The Include path expression must refer to a navigation property defined on the type.

+0

你可以做到這一點,但這需要構建包括手動的表達,這可能導致在相當長的一段代碼(雖然這代碼可能在以後類似的情況下重複使用我想)。 – Evk

回答

0

基於字符串的鏈接

可以用來拉一個完整的Include() method supports a dot-delimited string parameter將對象圖形向下,而不是進行多個鏈式選擇調用:

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

從那裏,如果你想包含多個附加屬性,我相信你可以有另一種包括那些子屬性:

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

基於LAMBDA鏈

你應該能夠通過你的鏈接來完成類似的λ-基於包括成一個單一的Include()通話以及使用:

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

+0

它與語法工作: .INCLUDE( 「LienContratSiteRef.Contrat.LienContratClientRef.Client.Telephones」).INCLUDE( 「LienContratSiteRef.Contrat.LienContratClientRef.Client.Mails」).INCLUDE(「LienContratSiteRef.Contrat.LienContratClientRef.Client .AppelRef「)缺點是模型更改時沒有編譯時錯誤。第二種形式Client.Mails,Client.AppelRef不起作用。我無法使用最後一個表單,因爲Contrat沒有LienContratSiteRef和LienContratClientRef的導航屬性。 – abreneliere

0

s => ...裏面的include可以被重構成一個委託,然後只是.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) 
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(); 
+0

我不能使用s.LienContratSiteRef.Contrat.LienContratClientRef.Client.Telephones語法,因爲LienContratSiteRef.Contrat和LienContratClientRef.Client是集合(我剛更新了問題以添加精度)。 – abreneliere

+0

啊!我會相應地更新答案。 – Ermish

相關問題