Repository模式的最佳实践 [英] Repository Pattern Best Practice

查看:183
本文介绍了Repository模式的最佳实践的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以我在实现一个应用程序存储库模式,并在我的模式的理解在两个问题来了:


  1. 查询 - 我读过,使用时库IQueryable的不应该使用的响应。但是,很明显,你会想,让你没有返回的对象每次调用方法时的完整列表。是否应该实施?如果我有一个名为List IEnumerable的方法,什么是一般的最佳实践为一个IQueryable?哪些参数应该/不应该有多少?


  2. 标量值 - 什么是最好的方式(使用存储库模式),而无需返回整个记录返回单,标值?从性能的角度来看,那岂不是更有效地在整个行返回只是一个单一的标量值?



解决方案

严格地说,一个库提供了集合的语义来获得/把域对象。它提供了周围的物化实现(ORM,手卷,模拟),以使域对象的消费者从这些细节解耦的抽象。在实践中,通常存储库访问抽象的实体,与身份即域对象,通常一个持久的生命周期(在DDD的味道,一库提供了访问聚合根)。

有关存储库的最小界面如下:

 无效添加(T实体);
无效删除(T实体);
ŧGetById(对象ID);
IEnumerable的< T>查找(规格规格);

虽然你会看到不同的命名和另外保存/ SaveOrUpdate语义,上面是纯粹的想法。你得到的ICollection的添加/删除成员加上一些发现者。如果你不使用IQueryable的,你还可以看到像库查找方法:

  FindCustomersHavingOrders();
FindCustomersHaving premiumStatus();

有在这种情况下使用IQueryable的两个相关的问题。首先是在域对象的关系,即违反迪米特法则的形式泄漏的实施细节,客户的潜力。第二是资源库获得可能不属于域对象找到责任适当的库,例如,发现有少比相关的数据请求的域对象的预测。

此外,使用IQueryable的'游'的模式:同一个IQueryable的仓库可能会或可能不会为域对象的访问。 IQueryable的给客户了很多关于当最终执行查询究竟会物化选项。这是关于使用IQueryable的辩论的主旨。

对于标量值,你不应该使用一个仓库返回标量值。如果你需要一个标量,您通常会从实体本身得到这个。如果这听起来很低效,它是,但你可能不会注意到,这取决于你的负载特性/要求。当你需要一个域对象的交替意见,因为性能原因,还是因为你需要从多个域对象合并数据时,你有两个选择的情况。

1)用实体的存储库来查找指定的实体和项目/映射到一个平展视图。

2)创建专用于返回一个封装所需的平面视图的新域类型取景器接口。这不会是一个仓库,因为就没有收藏的语义,但它可能会使用在幕后现有资源库。

一件事要考虑,如果你使用一个纯粹访问资源库中坚持实体是你妥协一些的ORM的好处。在纯的实现,客户端无法提供的域对象将如何使用环境,所以你不能告诉库:'嘿,我只是要改变customer.Name属性,因此不要T麻烦让那些急于加载引用。在另一面,问题是客户端是否应该知道的东西。这是一把双刃剑。

至于使用的IQueryable,大多数人似乎是舒服'断'的图案,以获得动态查询组合物的优点,特别是对客户的责任像寻呼/排序。在这种情况下,你可能有:

 添加(T实体);
删除(T实体);
ŧGetById(对象ID);
IQueryable的< T>找();

然后就可以与所有这些自定义的搜索方法,从而真正混乱的存储库作为你的查询需求的增长做了。

So I'm implementing the repository pattern in an application and came across two "issues" in my understanding of the pattern:

  1. Querying - I've read responses that IQueryable should not be used when using repositories. However, it's obvious that you'd want to so that you are not returning a complete List of objects each time you call a method. Should it be implemented? If I have an IEnumerable method called List, what's the general "best practice" for an IQueryable? What parameters should/shouldn't it have?

  2. Scalar values - What's the best way (using the Repository pattern) to return a single, scalar value without having to return the entire record? From a performance standpoint, wouldn't it be more efficient to return just a single scalar value over an entire row?

解决方案

Strictly speaking, a Repository offers collection semantics for getting/putting domain objects. It provides an abstraction around your materialization implementation (ORM, hand-rolled, mock) so that consumers of the domain objects are decoupled from those details. In practice, a Repository usually abstracts access to entities, i.e., domain objects with identity, and usually a persistent life-cycle (in the DDD flavor, a Repository provides access to Aggregate Roots).

A minimal interface for a repository is as follows:

void Add(T entity);
void Remove(T entity);
T GetById(object id);
IEnumerable<T> Find(Specification spec);

Although you'll see naming differences and the addition of Save/SaveOrUpdate semantics, the above is the 'pure' idea. You get the ICollection Add/Remove members plus some finders. If you don't use IQueryable, you'll also see finder methods on the repository like:

FindCustomersHavingOrders();
FindCustomersHavingPremiumStatus();

There are two related problems with using IQueryable in this context. The first is the potential to leak implementation details to the client in the form of the domain object's relationships, i.e., violations of the Law of Demeter. The second is that the repository acquires finding responsibilities that might not belong to the domain object repository proper, e.g., finding projections that are less about the requested domain object than the related data.

Additionally, using IQueryable 'breaks' the pattern: A Repository with IQueryable may or may not provide access to 'domain objects'. IQueryable gives the client a lot of options about what will be materialized when the query is finally executed. This is the main thrust of the debate about using IQueryable.

Regarding scalar values, you shouldn't be using a repository to return scalar values. If you need a scalar, you would typically get this from the entity itself. If this sounds inefficient, it is, but you might not notice, depending on your load characteristics/requirements. In cases where you need alternate views of a domain object, because of performance reasons or because you need to merge data from many domain objects, you have two options.

1) Use the entity's repository to find the specified entities and project/map to a flattened view.

2) Create a finder interface dedicated to returning a new domain type that encapsulates the flattened view you need. This wouldn't be a Repository because there would be no Collection semantics, but it might use existing repositories under the covers.

One thing to consider if you use a 'pure' Repository to access persisted entities is that you compromise some of the benefits of an ORM. In a 'pure' implementation, the client can't provide context for how the domain object will be used, so you can't tell the repository: 'hey, I'm just going to change the customer.Name property, so don't bother getting those eager-loaded references.' On the flip side, the question is whether a client should know about that stuff. It's a double-edged sword.

As far as using IQueryable, most people seem to be comfortable with 'breaking' the pattern to get the benefits of dynamic query composition, especially for client responsibilities like paging/sorting. In which case, you might have:

Add(T entity);
Remove(T entity);
T GetById(object id);
IQueryable<T> Find();

and you can then do away with all those custom Finder methods, which really clutter the Repository as your query requirements grow.

这篇关于Repository模式的最佳实践的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆