存储库模式和导航属性

时间:2011-03-13 23:22:12

标签: c# .net entity-framework repository-pattern entity-framework-ctp5

我只想知道编写存储库方法的最佳实践。问题是决定编写上下文没有延迟加载的存储库。如果它是GetById,你如何命名你的方法,但不清楚导航包含在实体中。

所以我想编写像GetUserByIdIncludedPosts这样的方法名称或者最好使用延迟加载激活的上下文?

如果我在方法名称中编写包含的属性,那么对于很少的导航属性来说,这将是非常烦人的长方法名称。

2 个答案:

答案 0 :(得分:2)

使用存储库模式并不意味着您将无法使用延迟加载。您仍然可以返回将能够延迟加载其相关实体的实体。唯一的要求是用于加载实体的DbContext必须是“活着的”。

但是让我们看看Martin Fowler

对存储库的定义
  

知识库在中间进行调解   行动的域和数据映射层   像内存中的域对象   采集。客户端对象构造   查询规范以声明方式和   将它们提交到Repository for   满足。可以添加对象   并从存储库中删除,如   他们可以从一个简单的集合   对象和映射代码   由Repository封装   进行适当的操作   在幕后。从概念上讲,   存储库封装了一组   对象持久存储在数据存储中   对他们进行的操作,   提供更面向对象的视图   持久层的。知识库   也支持的目标   实现清洁分离   域之间的单向依赖   和数据映射层。

我认为有趣的部分是:客户端对象以声明方式构造查询规范并将其提交到Repository以获得满意度。存储库通常也用于提供聚合根。因此,您将始终提供完整的根(并非总是可行),或者您将满足上述声明,并且您将通过Include上的IQueryable扩展方法在存储库之外定义热切加载。因此,您永远不需要像GetUserByIdIncludeSomething这样的专门方法。

如果您希望使用此方法为所有查询启动用户存储库:

public interface IRepository<T>
{
  IQueryable<T> GetQuery();
}

顺便说一下。我不认为用户是帖子的聚合根。在这种情况下,大多数应用程序将只有一个聚合根 - 一个用户。

修改

小说明:IQueryable默认情况下不提供Include方法。它在CTP5程序集中作为扩展方法提供,但如果您使用它,您将使您的上层依赖于EntityFramework.dll。这是你通常不想要的东西(你使用存储库的原因)。因此,要采用的方法是定义您自己的扩展方法,在程序集中使用您的存储库包装提供的扩展。

答案 1 :(得分:2)

我在我的存储库基类中使用以下内容,以允许检索实体以及用户指定的依赖关系/关系列表:

protected DbSet<T> Objects { get; private set; }
protected YourDatabaseContext Context { get; private set; }

public virtual T GetByID( int id, params string[] children )
{
    if( children == null || children.Length == 0 )
    {
        return Objects.SingleOrDefault( e => e.ID == id );
    }
    DbQuery<T> query = children.Aggregate<string, DbQuery<T>>( Objects, ( current, child ) => current.Include( child ) );
    return query.SingleOrDefault( e => e.ID == id );
}

代码使用EF4 / CTP5,因此使用Db *类,但转换回正常的EF4类(例如ObjectSet而不是DbSet)是微不足道的。

这样可以这样使用:

var product = productsRepository.GetByID( 42, "Category", "Orders.OrderLines" );

会向您提取已填充类别和订单的产品,以及所有订单都已急切加载OrderLines。