7

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

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

如果我在方法名中写入包含的属性,那么对于很少的导航属性来说真的很烦人的长方法名。

回答

2

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

但是,让我们对仓库的定义,看看通过Martin Fowler

版本库介导 域和数据映射层之间,作用 像在内存中的域对象 集合。客户对象以声明方式构造 查询规范,并将 提交给Repository,以获得 满意度。对象可以被添加到 并除去从所述存储库,因为 它们可以从 对象的简单集合,并且由存储库封装映射代码 将 进行适当的操作 幕后。从概念上讲,存储库封装了持久存储在数据存储中的对象集合 和通过它们执行的操作, 提供了持久层的更加面向对象的视图 。存储库 也支持 的目标实现域 和数据映射层之间的干净分离和 单向依赖性。

我觉得最有趣的部分是:客户对象构建查询规范声明,并提交给仓库中的满意度。库也通常用于提供聚合根。因此,您要么始终提供完整的根(不总是可能的),要么您将满足所提及的语句,并且您将通过Include扩展方法在IQueryable之上定义存储库以外的急切加载。正因为如此,你将永远不需要专门的方法,如GetUserByIdIncludeSomething

如果你想用户信息库开始用这种方法为所有查询:

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

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

编辑:

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

+0

如果您希望在数据层中保留与数据相关的异常,请不要这样做。由于延迟加载将在比洋葱结构主体将要颁布的更高层上执行。导致各种错误的行为。 还有其他的原因,如果你想观察关于这个话题的激情论证,那么简单的谷歌'存储库模式IQueryable'。 – Shadetheartist 2017-05-15 23:03:13

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即时加载的所有订单的产物。