【问题标题】:EF4, Lambda, Repository pattern and DTOsEF4、Lambda、存储库模式和 DTO
【发布时间】:2010-09-08 10:59:07
【问题描述】:

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

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

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

我的问题围绕 GUI 对 DTO 的使用(并且根本不让 GUI 使用实体),以及需要将 lambda 传递给数据层。我的数据层是带有 Add 的基本存储库模式。更改、删除、获取、GetList 等 尝试使用如下签名实现 Find 方法:

public IEnumerable<VideoDTO> Find(Expression<Func<VideoEntity, bool>> exp)
...
_dataModel.Videos.Where(exp).ToList<Video>()
---

我的问题/担忧是“exp”需要是 VideoEntity 类型而不是 VideoDTO。我想保留关注点的分离,以便 GUI 不知道实体对象。但是如果我尝试传入

Func<VideoDTO, bool> 

然后我无法使用实际数据模型对该表达式执行 LINQ Where。

有没有办法将Func&lt;VideoDTO,bool&gt; 转换为Func&lt;VideoEntity, bool&gt;

理想情况下,我的方法签名会接受Func&lt;VideoDTO, bool&gt;,这样GUI 就不会引用底层数据实体。

这足够清楚了吗?感谢您的帮助


感谢两位的回复。

我将尝试在对象中定义搜索条件并在 LINQ 表达式中使用它。刚开始使用 EF4 和 L2S,将其用作学习项目。

再次感谢!

【问题讨论】:

    标签: linq frameworks repository entity


    【解决方案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 是一些可能有帮助的想法(尽管与排序相关)。表情是相当复杂的野兽。

    无论如何 - 正如我所说,您应该避免这种情况。否则 - 你会产生非常脆弱的代码。

    【讨论】:

      【解决方案2】:

      也许您的设计目标是防止数据模型实体传播到客户端层,而不是防止表示层和数据模型之间的依赖关系。如果以这种方式查看,那么按照您所说的方式形成查询就没有任何问题。

      更进一步,您可以通过接口 (IVideoEntityQueryFields) 公开来自 VideoEntity 的可搜索字段,并将其用作表达式中的类型。

      如果您不想为实体添加接口,那么更复杂的选择是使用VideoEntityQuery 对象并将Expression&lt;Func&lt;VideoEntityQuery,bool&gt;&gt; 转换为Expression&lt;Func&lt;VideoEntity,bool&gt;&gt;

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-08-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-07-16
        • 2010-12-20
        • 1970-01-01
        • 2020-08-01
        相关资源
        最近更新 更多