繁体   English   中英

储存库模式和导航属性

[英]Repository pattern and Navigation properties

我只想了解有关编写存储库方法的最佳实践。 问题在于决定在上下文没有延迟加载的情况下编写存储库。 如果命名为GetById,但如何命名该方法,则不清楚该方法包含在实体中。

因此,我正在考虑编写类似GetUserByIdIncludedPosts的方法名称,还是最好使用延迟加载激活的上下文?

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

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

但是,让我们看一下Martin Fowler的存储库定义:

存储库在域和数据映射层之间进行中介,就像内存中的域对象集合一样。 客户端对象以声明方式构造查询规范,然后将其提交给存储库以使其满意。 可以像从简单的对象集合中那样将对象添加到存储库中或从存储库中删除对象,并且由存储库封装的映射代码将在后台执行适当的操作。 从概念上讲,存储库封装了持久存储在数据存储中的对象集以及对其执行的操作,从而提供了持久层的更面向对象的视图。 存储库还支持在域和数据映射层之间实现清晰的隔离和单向依赖的目标。

我认为有趣的部分是: 客户端对象以声明方式构造查询规范,然后将其提交给存储库以求满意 另外,存储库通常用于提供聚合根。 因此,您将始终提供完整的根目录(并非总是可能),或者将满足所提到的语句,并且将通过IQueryable Include扩展方法在存储库外部定义快速加载。 因此,您永远不需要像GetUserByIdIncludeSomething这样的专门方法。

如果要用户存储库,请针对所有查询使用此方法启动:

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

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

编辑:

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

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

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" );

它将获取您已填充“类别”和“订单”的产品,以及所有已热切加载其“订单行”的订单。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM