我有一个关于Entity Framework4,Lambda表达式和数据传输对象(DTO)的半复杂问题。
所以我有一个小的EF4项目,并遵循既定的OO原则,我有一个DTO,在数据使用者(GUI)和数据模型之间提供一个抽象层。
我的问题围绕着GUI使用DTO(而不是让GUI完全使用Entity),并且需要将lambda传递给数据层。我的数据层是Add的基本存储库模式。更改,删除,获取,获取列表等 尝试使用如下签名实现Find方法:
public IEnumerable<VideoDTO> Find(Expression<Func<VideoEntity, bool>> exp)
...
_dataModel.Videos.Where(exp).ToList<Video>()
---
我的问题/关注点是“exp”需要是VideoEntity而不是VideoDTO。我想保留关注点的分离,以便GUI不知道Entity对象。但如果我试图传入
Func<VideoDTO, bool>
然后我不能使用实际数据模型在那个表达式上做LINQ。
有没有办法将Func<VideoDTO,bool>
转换为Func<VideoEntity, bool>
理想情况下,我的方法签名会接受Func<VideoDTO, bool>
,这样GUI就不会引用底层数据实体。
这是否足够清楚?谢谢你的帮助
感谢你们双方的回复。
我将尝试在对象中定义搜索条件并在LINQ表达式中使用它。刚开始使用EF4和L2S,将其作为学习项目。
再次感谢!
答案 0 :(得分:1)
在像CQRS这样的架构中,根本不需要进行这样的转换。写应用程序的两面是分开的。
但在你的情况下,你不能逃避翻译。
首先 - 在定义存储库时应该更具体。存储库签名是您想要保持显式而不是通用的东西。
显示这个想法的常见示例 - 当您查看您的存储库签名时,您可以告诉您在数据库中需要哪些索引(可能正在查看存储库实现,但当然没有查看客户端代码)?你不能。因为它太通用了,客户端可以搜索任何东西。
在你的例子中,它更好一点,因为表达式泛化与dto而不是实体相关联。
这就是我所做的(使用NHibernate.Linq,但这个想法仍然存在)
public class Application{
public Project Project {get;set;}
}
public class ApplicationRepository{
public IEnumerable<Application> Search(SearchCriteria inp){
var c=Session.Linq<Application>();
var q=c.AsQueryable();
if(!string.IsNullOrEmpty(inp.Acronym))
q=q.Where(a=>a.Project.Acronym.Contains(inp.Acronym));
/*~20 lines of similar code snipped*/
return q.AsQueryable();
}
}
//used by client
public class SearchCriteria{
public string Acronym{get;set;}
/*some more fields that defines how we can search Applications*/
}
如果你想保留你的表达式,一种方法是手动定义字典,如下所示:
var d=new Dictionary<Expression<Func<VideoDTO,object>>,
Expression<Func<VideoEntity,object>>{
{x=>x.DtoPropNumberOne,x=>x.EntityPropNumberOne} /*, {2}, {3}, etc.*/
};
稍后再使用:
//can You spot it?
//client does not know explicitly what expressions dictionary contains
_dataModel.Videos.Where(d[exp]).ToList<Video>();
//and I'm not 100% sure checking expression equality would actually work
如果您不想手动编写映射字典,则需要一些高级技术。一个想法是将dto表达式转换为字符串,然后再转换回实体表达式。 Here是一些可能有所帮助的想法(虽然排序相关)。表达式是相当复杂的野兽。
无论如何 - 正如我所说,你应该避免这种情况。否则 - 你将生成非常脆弱的代码。
答案 1 :(得分:0)
也许您的设计目标是阻止数据模型实体传播到客户端层,而不是防止表示层和数据模型之间的依赖关系。如果以这种方式查看,那么查询的形成方式就没有任何问题。
为了更进一步,您可以通过接口(VideoEntity
)公开IVideoEntityQueryFields
中的可搜索字段,并将其用作表达式中的类型。
如果您不想为实体添加界面,则更复杂的选项是使用VideoEntityQuery
对象以及将Expression<Func<VideoEntityQuery,bool>>
转换为Expression<Func<VideoEntity,bool>>
的内容。< / p>