2010-02-09 93 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

相关问题