2010-02-09 91 views
1

我有一個實體框架3.5項目,我正在使用TPH繼承。我的兩個具體類型在它們自己的DAO類中,幷包含一個將實體類投影到DTO中的選擇器。但是,這兩個具體類與另一個表都有類似的關係,我使用let語句來清晰地標識。我的問題是,我能否以某種方式重構這個let語句,因爲當我創建更多繼承的具體類時,我覺得我違反了DRY。我可以在linq語句中重構範圍變量嗎?

StudentDAO.cs:

var myDTO = from x in context.Students 
let address = (from a in x.addresses where a.active == true select a).FirstOrDefault() 
select new StudentDTO { id = x.id, studentname = x.studentname, address = a.address}; 

ProfessorDAO.cs:

var myDTO = from x in context.Professors 
let address = (from a in x.addresses where a.active == true select a).FirstOrDefault() 
select new ProfessorDTO { id = x.id, professorname = x.studentname, address = a.address}; 

那麼有沒有一種方法,我可以重構地址了這兩個查詢的?

回答

2

簡短回答:恐怕沒有太多你可以很容易做。問題是你需要參數化查詢。然而,查詢需要表示爲表達式樹(以便它可以被轉換爲SQL或EF使用的任何東西)。不幸的是,C#沒有提供任何用於編寫表達式樹的優雅方法。前段時間,我寫了一篇解釋how to compose queries(使用一些技巧)的C#文章 - 您可以將表達式樹與拼接到一個參數化查詢中。因此,原則上可以使用本文中的技術創建一種方法,該方法將表達式樹的不斷變化的部分組成查詢。

我將使用LINQ中使用SQL的類型,因爲我更熟悉它,但我相信的原則應該是相同的:

IQueryable<R> GetInfo<T>(IQueryable<T> source, // e.g. context.Students 
    Expression<Func<T, IQueryable<Address>>> getAddr, // x => x.adresses 
    Expression<Func<T, Address, R>> getRes // (x, a) => new StudentDTO { ... } 
    return 
    from x in source.AsExpandable() 
    let address = (from a in getAddr(x).Expand() where a.active == true 
        select a).FirstOrDefault() 
    select getRes(x, a).Expand(); 
} 

// The use would look like this 
var res = GetInfo(context.Professors, x => x.addresses, (x, a) => new 
    ProfessorDTO { id = x.id, professorname = x.studentname, address = a.address }); 

所以總結是,C#和LINQ不要提供任何內置的支持,以使其更容易。但是,通過一些努力,您可以編寫由表達式樹的某些部分參數化的查詢。在你的情況下,它使代碼更短,重複性更低,但它使得它更加複雜(並且還需要使用庫,例如​​我提到的提供AsExpandableExpand的庫)。

在這種情況下,我擔心這是不值得的努力。但它會很好,如果C#v(下)^ x提供了一些更優雅的支持這樣的事情:-)

+0

鏈接的文章已經死了 – Fredou 2017-10-12 19:18:22

+0

@Fredou我會更新鏈接 - 它應該是http: //tomasp.net/blog/dynamic-linq-queries.aspx – 2017-10-13 00:25:11

相關問題