使用实体框架的最小存储库实现 [英] Minimal Repository implementation using Entity Framework

查看:66
本文介绍了使用实体框架的最小存储库实现的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在我的应用程序中实现最小的通用存储库模式。我有一个非常小的用于查询和保存数据的接口:

I'm trying to implement a minimal generic repository pattern in my application. I have a really small interface for querying and saving data:

public interface IRepository
{
    IQueryable<TEntity> Query<TEntity>() 
        where TEntity: BaseEntity;

    void Save<TEntity>(TEntity entity) 
        where TEntity : BaseEntity;
}

BaseEntity 是一个我将存储在存储库中的所有对象的基类:

BaseEntity is a base class for all the objects I will store in my repository:

public abstract class BaseEntity
{
    public Guid Id { get; set; }    
    public DateTime CreatedDate { get; set; }
    public DateTime UpdatedDate { get; set; }
}

我试图使用Entity找到这样一个简单存储库的有效实现框架,但是很难找到(人们正在使用 UnitOfWork 和其他使实现比我想要的复杂的东西)。

I was trying to find a working implementation of such a simple repository using Entity Framework, but it was surprisingly hard to find (people are using UnitOfWork and other things that make the implementation more complex than I want).

因此,我创建了我可以想到的绝对最小的实现:

So I created the absolutely minimal implementation I could come up with:

public class EfRepository : DbContext, IRepository
{
    public IQueryable<TEntity> Query<TEntity>() where TEntity : BaseEntity
    {
        return this.Set<TEntity>();
    }

    public void Save<TEntity>(TEntity entity) where TEntity : BaseEntity
    {
        if (entity.Id == default(Guid))
        {
            entity.Id = Guid.NewGuid();
            this.Set<TEntity>().Add(entity);
        }
        else
        {
            this.Entry(entity).State = EntityState.Modified;
        }       

        this.SaveChanges();
    }

    public DbSet<User> Users { get; set; } // User is a subclass of BaseEntity
    //Other DbSet's...
}

现在,我的问题是这样的实现是否正确。我之所以问是因为我是Entity Framework的新手,我担心使用此类存储库时可能出现的性能问题或可能出错的事情。

Now, my question is if such implementation is correct. I'm asking because I'm new to Entity Framework and I'm worried about possible performance issues or things that could possibly go wrong while using such repository.

注意:我尝试这样做的原因有两个:

Note: I'm trying to do all this for 2 reasons:


  • 出于测试目的,这样我就可以在自己的存储库中创建一个模拟了单元测试项目

  • 将来可能必须切换到另一个ORM,并且我想使这种转换尽可能容易。

推荐答案

首先,所有存储库都存在争议。有很多人强烈反对,并且出于各种原因有很多人使用它(或习惯了?)。互联网上有许多文章,都对利弊进行了无休止的讨论。由您决定是否在项目中确实需要存储库模式-当您询问如何在C#中执行此操作?时,请不要着重讨论该模式。不是我应该这样做吗?。

First of all repositories are controversial. There are lots of people strongly against and lots using it (or used to it?) for various reasons. There many articles over the internet with endless discussions about pros and cons. It's up to you to decide if you actually need the repository pattern in your project - let's not focus on that as you asked "how to do that in C#?" not "should i do that?".

您的存储库实现扩展了 DbContext 。这意味着您无法有效地创建一个跨越一个以上存储库(一种以上实体类型)的事务,因为每个存储库都将拥有其自己的 DbContext (因为它是上下文)。 DbContext 可以跟踪对实体所做的更改。如果您有多个上下文,并且尝试同时保存两个上下文,它们将不会彼此了解。这给我们带来了一个问题-如果 SaveChanges()的第一次调用成功,而第二次调用失败,如何回滚第一个?它已经保存了吗?

Your repository implementation extends DbContext. This means you cannot effectively create a transaction spanning more than one repository (more than one entity type) because each repository will have it's own DbContext (as it IS the context). Under the hood DbContext tracks changes made to the entities. If you have more than one context and try to save both at the same time they won't know about each other. This leaves us with a problem - if the first call of SaveChanges() succeeds and second fails how to rollback the first one? It was already saved?. That's where the unit of work appears.

所以首先需要一个存储库接口-充当实体的集合:

So first you need a repository interface - acting as a collection of entities:

public interface IRepository<TEntity>
{
    TEntity Get(Expression<Func<TEntity, bool>> predicate);
    IEnumerable<TEntity> GetAll();
    IEnumerable<TEntity> GetAll(Expression<Func<TEntity, bool>> predicate);

    void Add(TEntity entity);
    void AddAll(IEnumerable<TEntity> entities);

    void Remove(TEntity entity);
    void RemoveAll(IEnumerable<TEntity> entities);
}

工作单位:

public interface IUnitOfWork : IDisposable
{
    // Commit all the changes 
    void Complete();

    // Concrete implementation -> IRepository<Foo>
    // Add all your repositories here:
    IFooRepository Foos {get;}
}

基类如下:

public class BaseRepository<TEntity> : IRepository<TEntity> where TEntity : class
{
    protected DbContext Context { get; private set; }

    public BaseRepository(DbContext dbContext)
    {
        Context = dbContext;
    }

    public virtual TEntity Get(Expression<Func<TEntity, bool>> predicate)
    {
        return Context.Set<TEntity>().Where(predicate).FirstOrDefault();
    }

    public virtual IEnumerable<TEntity> GetAll()
    {
        return Context.Set<TEntity>().ToList();
    }

    public virtual IEnumerable<TEntity> GetAll(Expression<Func<TEntity, bool>> predicate)
    {
        return Context.Set<TEntity>().Where(predicate).ToList();
    }

    public void Add(TEntity entity)
    {
        var entry = Context.Entry(entity);
        if(entry.State == EntityState.Detached)
        {
            Context.Set<TEntity>().Add(entity);
        }
        else
        {
            entry.State = EntityState.Modified;
        }
    }

    public void AddAll(IEnumerable<TEntity> entities)
    {
        foreach(var entity in entities)
        {
            Add(entity);
        }
    }

    public void Remove(TEntity entity)
    {
        var entry = Context.Entry(entity);
        if (entry.State == EntityState.Detached)
        {
            Context.Set<TEntity>().Attach(entity);
        }
        Context.Entry<TEntity>(entity).State = EntityState.Deleted;
    }

    public void RemoveAll(IEnumerable<TEntity> entities)
    {
        foreach (var entity in entities)
        {
            Remove(entity);
        }
    }

}

和单位工作实现的实现:

And Unit of work implementation:

public class UnitOfWork : IUnitOfWork
{
    private readonly ApplicationDbContext _dbContext;
    private IFooRepository _fooRepo;

    public UnitOfWork(ApplicationDbContext dbContext)
    {
        _dbContext = dbContext;

        // Each repo will share the db context:
        _fooRepo = new FooRepository(_dbContext);
    }


    public IFooRepository Foos
    {
        get
        {
            return _fooRepo;
        }
    }

    public void Complete()
    {
        _dbContext.SaveChanges();
    }

    public void Dispose()
    {
        _dbContext.Dispose();
    }
}

这篇关于使用实体框架的最小存储库实现的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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