使用DDD和IoC实现EF4的存储库 [英] Implementing repository for EF4 using DDD and IoC

本文介绍了使用DDD和IoC实现EF4的存储库的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



我正在使用一个MVC 3解决方案,使用EF4& POCO(数据库优先)和IoC。我的存储库和UoW模式大多从这篇文章这篇文章



我的解决方案由以下项目组成:



实施:




  • 演示文稿(MVC网站)

  • 域名服务(业务层)

  • 域信息库(数据访问)

  • 域上下文(我的EF4 edmx和生成的上下文)

  • 域模型(我的EF4生成的POCO)



接口:



< (>数据访问接口)
  • 域上下文接口(生成接口ed EF4上下文)



  • 最后,IoC项目将所有内容联系起来。



    如果您在第一篇文章中注意到,作者提及从域服务中删除对ObjectSet的依赖关系。我假设这是为了可测试性。但是,这样做的问题是,它阻碍了从域服务执行复杂查询的能力,因为IObjectSet和IEnumerable(由存储库中的大多数方法返回)不会存储复杂查询的方法。



    这是否意味着我应该在我的存储库中进行复杂的查询?我应该离开诸如 public T Single(Expression< Func< T,bool>> where)之类的方法,并坚持使用 public T GetUserById (int id)



    如果不是这样,那么我如何做复杂的查询如此



    看看我上面的解决方案大纲和问题,我正在朝着正确的方向前进,还是为自己创造问题?



    提前感谢

    解决方案

    这是主观/意见的问题,但您可以使您的存储库返回 IQueryable< T> ,那么你可以这样做你的服务中的复杂查询:

      return _repository // IRepository< T> 
    .Find()// IQueryable< T>
    .Where(someComplexPredicate)// IQueryable< T>
    .SingleOrDefault(); // T

    ObjectSet< T> IQueryable< T> ,这使得这成为可能。



    如果你想开始做对象集< T> 您服务中的特定内容,您有两个选择:


    1. code> ObjectSet< T> 特定方法作为您的Repository界面上的方法

    2. 使用 IQueryable< T& / code>扩展方法做一个软转换到 ObjectSet< T> (例如 var objSet = source as ObjectSet< T>

    始终尝试使用选项1。



    完美的例子是渴望加载。在 ObjectContext< T> 中有一个叫 Include 的方法,所以如果你使用 IQuerayable< ;您的存储库中的T> ,您如何加载?



    由于 Include 使用魔术字符串,您可以在您的存储库中的 Find 方法中接受此操作,例如:

      return _repository // IRepository< T> 
    .Find(Product.Orders)// IQueryable< T>
    .Where(someComplexPredicate)// IQueryable< T>
    .SingleOrDefault();幸运的是,在EF CTP5中,他们引入了一个强类型的包含可以在 IQueryable< T> 中运行,所以当我切换时,我不需要执行上述操作。



    正如我所说,最好的办法是在Repository界面上公开方法。但是需要做一个权衡 - 一个接口应该是一个服务的合同或定义,而不是关于这个隐含的。所以EF特定的事情应该通过扩展方法来完成。一般事情可以通过存储库界面完成。


    I think I'm going in circles.

    I'm working on an MVC 3 solution using EF4 & POCOs (database-first) and IoC. My repository and UoW patterns were mostly adopted from this article and this article.

    My solution is made up of the following projects:

    Implementations:

    • Presentation (MVC site)
    • Domain Services (business layer)
    • Domain Repository (data access)
    • Domain Context (my EF4 edmx and generated context)
    • Domain Models (my EF4 generated POCOs)

    Interfaces:

    • Domain Services Interfaces (business layer interfaces)
    • Domain Repository Interfaces (data access interfaces)
    • Domain Context Interfaces (interfaces for generated EF4 context)

    And lastly, the IoC project that ties everything together.

    If you notice in that first article, the author mentions removing the dependency on ObjectSet from the domain services. This, I'm assuming, is for testability. Problem with this, though, is that it hinders the ability to do complex queries from the domain services, because IObjectSet and IEnumerable (returned by most methods on repository) don't stub out methods for complex querying.

    Does this imply that I should be doing my complex querying in my repository? Should I move away from methods like public T Single(Expression<Func<T, bool>> where) and stick to methods like public T GetUserById(int id)?

    If this is not the case, then how do I do complex queries such as this in my service layer?

    Looking at my solution outline above and the questions I have, am I moving in the right direction, or am I creating problems for myself?

    Thanks in advance.

    解决方案

    This is subjective/matter of opinion, but you could make your Repository return IQueryable<T>, then you can do your "complex queries" in your service like this:

    return _repository // IRepository<T>
              .Find() // IQueryable<T>
              .Where(someComplexPredicate) // IQueryable<T>
              .SingleOrDefault(); // T
    

    ObjectSet<T> : IQueryable<T>, which makes this possible.

    If you want to start doing ObjectSet<T>-specific things in your service, you've got two options:

    1. Expose the ObjectSet<T>-specific method as a method on your Repository interface
    2. Use an IQueryable<T> extension method to do a "soft cast" to ObjectSet<T> (e.g var objSet = source as ObjectSet<T>).

    Always try and go with option 1.

    Perfect example is eager loading. There is a method called Include on the ObjectContext<T>, so if you use IQuerayable<T> in your Repository, how do you eager load?

    Since Include takes a "magic string", you could accept this in your Find method on your Repository, e.g:

    return _repository // IRepository<T>
              .Find("Product.Orders") // IQueryable<T>
              .Where(someComplexPredicate) // IQueryable<T>
              .SingleOrDefault(); // T
    

    Fortunately in EF CTP5 they have introduced a strongly-typed Include which works off IQueryable<T>, so i didn't have to do the above when i cutover.

    So as i said, best thing to do is expose methods on your Repository interface. But there needs to be a tradeoff - an interface should be a "contract" or "definition" of a service, not about the implmentation. So EF-specific things should be done via extension methods. General things can be done via the repository interface.

    这篇关于使用DDD和IoC实现EF4的存储库的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆