[翻译]  Repository Pattern pros and cons of each implementation

[CHINESE]  存储库模式每个实现的优缺点


Hi looking at the repository pattern which commonly seems to be implemented something like:

嗨,看看通常似乎实现的存储库模式,如:

public class GenericRepository<TEntity> where TEntity : class
{
    // other business

    public virtual TEntity GetByID(object id)
    {
        return db.Set().Find(id);
    }

    public virtual void Insert(TEntity entity)
    {
        db.Set().Add(entity);
    }

    public virtual void Delete(object id)
    {
        TEntity entityToDelete = db.Set().Find(id);
        Delete(entityToDelete);
    }

    public virtual void Update(TEntity entityToUpdate)
    {
        db.Set().Attach(entityToUpdate);
        context.Entry(entityToUpdate).State = EntityState.Modified;
    }
}

So for every type you want to work with (ie update) you need to instantiate a repository.

因此,对于您要使用的每种类型(即更新),您需要实例化存储库。

So if I had two types I wanted to save Cars and Trucks I would need to go:

所以,如果我有两种类型,我想保存汽车和卡车,我需要去:

var carRepository = new GernericRepository<Car>();
carRepository.Update(myCar);

var truckRepository = new GernericRepository<Truck>();
carRepository.Update(myTruck);

So then you have seperate repositories for each type. To make sure you save everything at once you need the unitOfWork to ensure they all use the same context and save at one time.

那么你就为每种类型都有单独的存储库。要确保一次保存所有内容,您需要unitOfWork以确保它们都使用相同的上下文并一次保存。

Surely wouldn't it be better to have something like:

当然不会有更好的东西,如:

public class GenericRepository
{
    // other business

    public virtual TEntity GetByID<TEntity>(object id) where TEntity : class
    {
        return db.Set<TEntity>().Find(id);
    }

    public virtual void Insert<TEntity>(TEntity entity) where TEntity : class
    {
        db.Set<TEntity>().Add(entity);
    }

    public virtual void Delete<TEntity>(object id) where TEntity : class
    {
        TEntity entityToDelete = db.Set<TEntity>().Find(id);
        Delete(entityToDelete);
    }

    public virtual void Update<TEntity>(TEntity entityToUpdate) where TEntity : class
    {
        db.Set<TEntity>().Attach(entityToUpdate);
        context.Entry(entityToUpdate).State = EntityState.Modified;
    }
}

This means the repository only needs to be instantiated once and therefore is truely generic?

这意味着存储库只需要实例化一次,因此是真正的通用?

So you could update your cars and trucks like this:

所以你可以这样更新你的汽车和卡车:

var repository = new GernericRepository<Car>();
repository.Update<Car>(myCar);
rRepository.Update<Truck>(myTruck);

Surely this is a better method? Am I missing something? It automatically has only one context too.

当然这是一个更好的方法?我错过了什么吗?它自动也只有一个上下文。

2 个解决方案

#1


6  

The repository pattern does not decouple the data access from the data store, that is what the ETL tool such as NHibernate or the Enity Framework does for. The repository pattern provides reusable methods for extracting data.

存储库模式不会将数据访问与数据存储分离,这就是NHIBnate或Enity Framework等ETL工具所做的事情。存储库模式提供了可重用的数据提取方法。

I have previously used a so called "Generic" repository as you have described and thought it was great. It isn't until you realise that you have just put another layer on top of NHibernate or the Entity Framework you realise it's all gone Pete Tong.

我之前使用了一个所谓的“通用”存储库,如你所描述并认为它很棒。直到你意识到你刚刚在NHibernate或实体框架之上放置了另一层,你才意识到它已经全部消失了Pete Tong。

Ideally what you want are interfaces that describe ways of getting data out of your data store and should not leak what data access you are using. For example:

理想情况下,您需要的是描述从数据存储中获取数据的方式的接口,并且不应泄漏您正在使用的数据访问。例如:

public interface IEmployee interface
{
    IEmployee GetEmployeeById(Guid employeeId);

    IEmployee GetEmployeeByEmployeeNumber(string employeeNumber);

    IEnumerable<IEmployee> GetAllEmployeesWithSurname(string surname);

    IEnumerable<IEmployee> GetAllEmployeesWithStartDateBetween(DateTime beginDateTime, DateTime endDateTime);
}

This gives you a contract to code to, there is no knowledge of your persistence layer and the queries used to retrieve the data can be unit tested in isolation. The interface could inherit from a base interface that provides common CRUD methods but you would be assuming that all your repositories would need CRUD.

这为您提供了代码合同,您不了解持久层,并且用于检索数据的查询可以单独进行单元测试。接口可以从提供常见CRUD方法的基接口继承,但您可以假设所有存储库都需要CRUD。

If you go down the road of a Generic Repository you will end up with duplication in your queries and you will find it much harder to unit test the code that uses the repository as you will have to test the queries as well.

如果你走在通用存储库的道路上,你最终会在查询中出现重复,你会发现使用存储库的代码进行单元测试要困难得多,因为你也必须测试查询。

#2


1  

Generics by itself does not make an implementation of the repository pattern. We've all seen the generic base class used in example repository pattern implementations but this is to make things DRY (Don't-Repeat-Yourself) by inheriting from the base class ( GenericRepository in your case) to more specialized child classes.

泛型本身并不构成存储库模式的实现。我们都看到了示例存储库模式实现中使用的通用基类,但这是通过从基类(在您的情况下为GenericRepository)继承到更专业的子类来使事情干(不要重复自己)。

Only using the generic, base class GenericRepository assumes that your repositories will only ever need the most basic CRUD methods. For a more complex system, each repository becomes more specialized based on underlying business entities data requirements.

只使用通用的基类GenericRepository假定您的存储库只需要最基本的CRUD方法。对于更复杂的系统,每个存储库根据底层业务实体数据要求变得更加专业化。

Also, you will need to have interfaces that define your data contracts with your other layers. Using the repository pattern means you don't want to expose your concrete implementations of your repositories to your other layers.

此外,您还需要具有与其他图层定义数据合同的接口。使用存储库模式意味着您不希望将存储库的具体实现公开给其他层。


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
© 2014-2018 ITdaan.com 粤ICP备14056181号