简体   繁体   English

储存库模式和导航属性

[英]Repository pattern and Navigation properties

I just want know best practice about writing repository methods. 我只想了解有关编写存储库方法的最佳实践。 Problem is deciding to write repository in which context has no lazy loading. 问题在于决定在上下文没有延迟加载的情况下编写存储库。 How do you naming your method if it is GetById but it is not clear that which the navigations included in entity. 如果命名为GetById,但如何命名该方法,则不清楚该方法包含在实体中。

So I am thinking to write method names like GetUserByIdIncludedPosts Or it is better to use lazy loading activated context ? 因此,我正在考虑编写类似GetUserByIdIncludedPosts的方法名称,还是最好使用延迟加载激活的上下文?

If I write included properties in method names so will be really annoying long method names for few navigation property. 如果我在方法名称中写入包含的属性,那么对于很少的导航属性来说,长方法名称确实会很烦人。

Using repository pattern doesn't mean that you will not be able to use lazy loading. 使用存储库模式并不意味着您将无法使用延迟加载。 You can still return entity which will be able to lazy load its related entities. 您仍然可以返回实体,该实体将能够延迟加载其相关实体。 The only requirement is that DbContext used for loading entity must be "alive". 唯一的要求是用于加载实体的DbContext必须是“活动的”。

But let's have a look on definition of repository by Martin Fowler : 但是,让我们看一下Martin Fowler的存储库定义:

A Repository mediates between the domain and data mapping layers, acting like an in-memory domain object collection. 存储库在域和数据映射层之间进行中介,就像内存中的域对象集合一样。 Client objects construct query specifications declaratively and submit them to Repository for satisfaction. 客户端对象以声明方式构造查询规范,然后将其提交给存储库以使其满意。 Objects can be added to and removed from the Repository, as they can from a simple collection of objects, and the mapping code encapsulated by the Repository will carry out the appropriate operations behind the scenes. 可以像从简单的对象集合中那样将对象添加到存储库中或从存储库中删除对象,并且由存储库封装的映射代码将在后台执行适当的操作。 Conceptually, a Repository encapsulates the set of objects persisted in a data store and the operations performed over them, providing a more object-oriented view of the persistence layer. 从概念上讲,存储库封装了持久存储在数据存储中的对象集以及对其执行的操作,从而提供了持久层的更面向对象的视图。 Repository also supports the objective of achieving a clean separation and one-way dependency between the domain and data mapping layers. 存储库还支持在域和数据映射层之间实现清晰的隔离和单向依赖的目标。

I think the interesting part is: Client objects construct query specifications declaratively and submit them to Repository for satisfaction . 我认为有趣的部分是: 客户端对象以声明方式构造查询规范,然后将其提交给存储库以求满意 Also repository is usually used to provide aggregate roots. 另外,存储库通常用于提供聚合根。 So you will either always provide whole root (not always possible) or you will satisfy the mentioned statement and you will define eager loading outside of the repository by Include extension method on IQueryable . 因此,您将始终提供完整的根目录(并非总是可能),或者将满足所提到的语句,并且将通过IQueryable Include扩展方法在存储库外部定义快速加载。 Because of that you will never need specialized methods like GetUserByIdIncludeSomething . 因此,您永远不需要像GetUserByIdIncludeSomething这样的专门方法。

If you want to user repository start with this method for all queries: 如果要用户存储库,请针对所有查询使用此方法启动:

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

Btw. 顺便说一句。 I don't think that a user is aggregate root for posts. 我认为用户不是帖子的聚合根。 In such case the most of applications will have only single aggregate root - a user. 在这种情况下,大多数应用程序将只有一个聚合根-一个用户。

Edit: 编辑:

Small clarification: IQueryable by default doesn't provide Include method. 简要说明:默认情况下, IQueryable不提供Include方法。 It is provided as extension method in CTP5 assembly but if you use it you will make your upper layer dependent on EntityFramework.dll. 它作为CTP5程序集中的扩展方法提供,但是如果使用它,则将使上层依赖EntityFramework.dll。 It is something you usually don't want (the reason why you are using repository). 这通常是您不想要的(使用存储库的原因)。 So the way to go is define your own extension method wrapping provided extension in assembly with your repository. 因此,要走的路是定义自己的扩展方法,将提供的扩展包装到存储库中。

I am using the following in my repository base class to allow retrieval of entities along with a user-specified list of dependencies/relations: 我在存储库基类中使用以下内容,以允许检索实体以及用户指定的依赖关系/关系列表:

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

The code uses EF4/CTP5 and therefore uses Db* classes, but is trivial to convert back to the normal EF4 classes (eg ObjectSet instead of DbSet). 该代码使用EF4 / CTP5,因此使用Db *类,但是可以轻松转换回普通EF4类(例如ObjectSet而不是DbSet)。

This would be used like so: 可以这样使用:

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

which would fetch you a product with Category and Orders populated as well as all orders having their OrderLines eagerly loaded. 它将获取您已填充“类别”和“订单”的产品,以及所有已热切加载其“订单行”的订单。

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

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