EF4,Lambda,存储库模式和DTO

时间:2010-09-08 10:59:08

标签: linq frameworks repository entity

我有一个关于Entity Framework4,Lambda表达式和数据传输对象(DTO)的半复杂问题。

所以我有一个小的EF4项目,并遵循既定的OO原则,我有一个DTO,在数据使用者(GUI)和数据模型之间提供一个抽象层。

  • VideoDTO =带有getter / setter的DTO,由GUI使用
  • VideoEntity =由EF4生成的实体

我的问题围绕着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,将其作为学习项目。

再次感谢!

2 个答案:

答案 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>