我只想知道编写存储库方法的最佳实践。问题是决定编写上下文没有延迟加载的存储库。如果它是GetById,你如何命名你的方法,但不清楚导航包含在实体中。
所以我想编写像GetUserByIdIncludedPosts这样的方法名称或者最好使用延迟加载激活的上下文?
如果我在方法名称中编写包含的属性,那么对于很少的导航属性来说,这将是非常烦人的长方法名称。
答案 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。