具有 EntityFramework 的通用存储库

     2023-04-12     143

关键词:

【中文标题】具有 EntityFramework 的通用存储库【英文标题】:Generic Repository with EntityFramework 【发布时间】:2017-08-07 10:45:53 【问题描述】:

我想使用实体框架实现一个通用的存储库模式(我知道关于存储库有很多有争议的观点,但这仍然是我需要的)。 我想要的界面如下:

public interface IRepository

    IQueryable<TEntity> Query<TEntity>() 
        where TEntity: Entity;

    void Save<TEntity>(TEntity entity) 
        where TEntity : Entity;

    void Delete<TEntity>(TEntity entity) 
        where TEntity : Entity;

Entity 是一个只有int ID 属性的基类。 并像这样使用它:

        IRepository repository = ... // get repository (connects to DB)
        int userId = GetCurrentUserId();
        if (!repository.Query<User>().Any(u => u.Id == userId)) // performs SELECT query
            /*return error*/    

        var newOrder = new Order  UserId = userId, Status = "New" 
        repository.Save(newOrder); // performs INSERT query
        ...
        newOrder.Status = "Completed";
        repository.Save(newOrder); // performs UPDATE query

我想避免UnitOwWork,只要调用Save()Delete() 就将所有对象更改提交到数据库。我想做的事情看起来很简单,但我没有找到任何使用 EntityFramework 的示例。我能找到的最接近的示例是 this answer,但它使用 UnitOwWork 和 repository-per-entity,其中比我需要做的更复杂。

【问题讨论】:

如果你想保持简单,那么不要在实体框架中使用存储库模式。实体框架本身已经是一个存储库模式,您只是在现有抽象之上添加更多抽象,它没有任何好处。相反,它可能会使您的代码更难维护和使用,同时增加开发额外不必要层的成本。 这不是一个通用存储库,它只是一个 DbContext 的包装器。我很好奇您是如何实现Save 的,因为它表明您可以有选择地保存一个实体,即使上下文包含更多已更改的实体。难以置信。如果可以的话,这违背了SaveChanges 方法的目的。 @GertArnold,接口一个存储库。我已经使用纯 ADO.NET 和 Dapper 实现了其中的一部分。 (顺便说一句,这是我想要对 EF 进行抽象的原因之一:我的应用程序的某些部分包含 EF 不完全支持的复杂查询,但我希望使用一个抽象来执行所有查询:IRepository)IRepository 不知道或关心 EF 或 DbContext。它应该是所有数据操作的通用简单接口(这在后台可能非常复杂 - 就像为不同的实体类型使用不同的 ORM)。 @Nazz IQueryable 将使用带有实现(f.i. EF)的 IRepository 接口“感染”您的代码。它不再那么抽象了 @Nazz 所以你是说在你的存储库抽象背后你可以有 EF 或 Dapper? 【参考方案1】:

1-创建一个接口

interface IMain<T> where T : class
    
        List<T> GetAll();
        T GetById(int id);
        void Add(T entity);
        void Edit(T entity);
        void Del(int id);
        int Savechange();
    

2-创建一个类

public class Main<T> : IMain<T> where T : class
    
        public DataContext db;
        public void Add(T entity)
        
            db.Set<T>().Add(entity);
        

        public void Del(int id)
        
            var q = GetById(id);
            db.Set<T>().Remove(q);
        

        public void Edit(T entity)
        
            db.Entry<T>(entity).State = EntityState.Modified;
        

        public List<T> GetAll()
        
            return db.Set<T>().Select(a=>a).ToList();
        

        public T GetById(int id)
        
            return db.Set<T>().Find(id);
        

        public int Savechange()
        
            return db.SaveChanges();
        
    

3-创建一个名为 YourTable ForExample Student

的存储库
 public class Student : Main<Tbl_Student>
    
        public Student()
        
            db = new DataContext();
        
    

4-为您的行动编写此代码

Student student=new Student();
student.Del(3);
int a = student.Savechange();

【讨论】:

【参考方案2】:

您可以使用表达式关键字来做到这一点;

    public interface IRepository<TEntity> where TEntity : Entity
    
        IQueryable<TEntity> Query(Expression<Func<TEntity, bool>> predicate);

        void Save(TEntity entity);

        void Delete(TEntity entity);
    

    public abstract class EfRepository<T> : IRepository<T> where T : Entity
    
        private readonly DbContext _dbContext;
        protected readonly DbSet<T> _dbSet;
        public EfRepository(YourDbContextContext dbContext)
        
            _dbContext = dbContext;
            _dbSet = dbContext.Set<T>();
        

        public void Delete(T entity)
        
            if (entity == null) return;
            else
            
                DbEntityEntry dbEntityEntry = _dbContext.Entry(entity);

                if (dbEntityEntry.State != EntityState.Deleted)
                
                    dbEntityEntry.State = EntityState.Deleted;
                
                else
                
                    _dbSet.Attach(entity);
                    _dbSet.Remove(entity);
                    _dbContext.SaveChanges();
                
            
        

        public IQueryable<T> Query(Expression<Func<T, bool>> predicate)
        
            return _dbSet.Where(predicate);
        

        public void Save(T entity)
        
            if (entity.Id > 0)
            
                _dbSet.Attach(entity);
                _dbContext.Entry(entity).State = EntityState.Modified;
                _dbContext.SaveChanges();
            
            else
            
                _dbSet.Add(entity);
                _dbContext.SaveChanges();
            
        
    
    public class Entity
    
        public int Id  get; set; 
    

然后创建您的存储库;

     public interface IUserRepository : IRepository<User>
     
       //Also you can add here another methods according to your needs
     
     public class UserRepository : EfRepository<User>,IUserRepository
     
            public UserRepository(YourDbContext yourDbContext) : base(yourDbContext)
            

            
     

那就用吧;

IUserRepository _userRepository => Getit
//If there are entities according to your conditions, this will return them, then use it
_userRepository.Query(u => u.Id == userId);

【讨论】:

【参考方案3】:

我曾经使用它,但正如许多开发人员所说,它会增加代码的复杂性并可能导致问题:

我的interface IRepositoryBase的代码:

public interface IRepositoryBase<TEntity> where TEntity : class

    void Add(TEntity objModel);
    void AddRange(IEnumerable<TEntity> objModel);
    TEntity GetId(int id);
    Task<TEntity> GetIdAsync(int id);
    TEntity Get(Expression<Func<TEntity, bool>> predicate);
    Task<TEntity> GetAsync(Expression<Func<TEntity, bool>> predicate);
    IEnumerable<TEntity> GetList(Expression<Func<TEntity, bool>> predicate);
    Task<IEnumerable<TEntity>> GetListAsync(Expression<Func<TEntity, bool>> predicate);
    IEnumerable<TEntity> GetAll();
    Task<IEnumerable<TEntity>> GetAllAsync();
    int Count();
    Task<int> CountAsync();
    void Update(TEntity objModel);
    void Remove(TEntity objModel);
    void Dispose(); 

我的interface 在repsoitory RepositoryBase 上的实现代码:

public class RepositoryBase<TEntity> : IRepositoryBase<TEntity> where TEntity : class

    #region Fields

    protected readonly EntityContext _context = new EntityContext();

    #endregion

    #region Methods

    public void Add(TEntity objModel)
    
        _context.Set<TEntity>().Add(objModel);
        _context.SaveChanges();
    

    public void AddRange(IEnumerable<TEntity> objModel)
    
        _context.Set<TEntity>().AddRange(objModel);
        _context.SaveChanges();
    

    public TEntity GetId(int id)
    
        return _context.Set<TEntity>().Find(id);
    

    public async Task<TEntity> GetIdAsync(int id)
    
        return await _context.Set<TEntity>().FindAsync(id);
    

    public TEntity Get(Expression<Func<TEntity, bool>> predicate)
    
        return _context.Set<TEntity>().FirstOrDefault(predicate);
    

    public async Task<TEntity> GetAsync(Expression<Func<TEntity, bool>> predicate)
    
        return await _context.Set<TEntity>().FirstOrDefaultAsync(predicate);
    

    public IEnumerable<TEntity> GetList(Expression<Func<TEntity, bool>> predicate)
    
        return _context.Set<TEntity>().Where<TEntity>(predicate).ToList();
    

    public async Task<IEnumerable<TEntity>> GetListAsync(Expression<Func<TEntity, bool>> predicate)
    
        return await Task.Run(() =>
            _context.Set<TEntity>().Where<TEntity>(predicate));
    

    public IEnumerable<TEntity> GetAll()
    
        return _context.Set<TEntity>().ToList();
    

    public async Task<IEnumerable<TEntity>> GetAllAsync()
    
        return await Task.Run(() => _context.Set<TEntity>());
    

    public int Count()
    
        return _context.Set<TEntity>().Count();
    

    public async Task<int> CountAsync()
    
        return await _context.Set<TEntity>().CountAsync();
    

    public void Update(TEntity objModel)
    
        _context.Entry(objModel).State = EntityState.Modified;
        _context.SaveChanges();
    

    public void Remove(TEntity objModel)
    
        _context.Set<TEntity>().Remove(objModel);
        _context.SaveChanges();
    

    public void Dispose()
    
        _context.Dispose();
    

    #endregion

我的实体interface

public interface IMyEntityRepository : IRepositoryBase<MyEntity>

     //here you can place other implementations your repository doesn't have


public class MyEntityRepository : RepositoryBase<MyEntity>, IMyEntityRepository


如何调用(我用的是依赖注入):

public class MyServiceOrController

    #region Fields

    private readonly IMyEntityRepository _myEntityRepository;

    #endregion

    #region Constructors

    public MyServiceOrController(IMyEntityRepository myEntityRepository)
    
        _myEntityRepository = myEntityRepository;
    

    #endregion

    #region Methods

    public IList<MyEntity> TestGetAll()
    
        return _myEntityRepository.GetAll();
    

    #endregion

【讨论】:

带有 ThenIncludes 的通用存储库模式

...一是我实现存储库模式的DataAccess层。我的主要关注点是EntityFramework仅在DataAccess层中被引用。我需要在查询中包含关系,因此我调整了查询​​方法以接收Includes作为输入。 查看详情

通用存储库、工作单元、Unity 的架构问题

...时间】:2019-01-0614:49:36【问题描述】:我正在使用MVC5、EntityFramework、Unity、UnitOfWork和GenericRepository开发我的项目架构之一,而且我还没有使用AutoMapper或任何其他类似于AutoMa 查看详情

访问存储库中的 UnitOfWork 是不好的设计吗?

...itory?【发布时间】:2013-05-0218:24:09【问题描述】:背景:Entityframework4.1和MVC4我的设置有模型实体,然后是通用存储库,然后是从通用存储库继承的UserRepository、ProductRepository等特定存储库的模型。 查看详情

java示例代码_Wrap Play/JPA';具有通用存储库的s模型类

java示例代码_Wrap Play/JPA';具有通用存储库的s模型类 查看详情

ASP.NET MVC,EntityFramework,DBContext,不同项目中的存储库[关闭]

】ASP.NETMVC,EntityFramework,DBContext,不同项目中的存储库[关闭]【英文标题】:ASP.NETMVC,EntityFramework,DBContext,RepositoryinadifferentProject[closed]【发布时间】:2013-11-0710:18:08【问题描述】:我目前正在开发一个ASP.NETMVC5项目,我正在尝试... 查看详情

具有实体框架 4.1 和父/子关系的存储库模式

】具有实体框架4.1和父/子关系的存储库模式【英文标题】:RepositoryPatternwithEntityFramework4.1andParent/ChildRelationships【发布时间】:2011-11-0212:23:45【问题描述】:我仍然对存储库模式有些困惑。我想使用此模式的主要原因是避免从域... 查看详情

在entityframework4中使用存储库/uow模式的多个objectcontexts(代码片段)

我在asp.netWeb应用程序中使用EF4和StructureMap。我正在使用工作模式的存储库/单元作为detailedinthispost。在代码中,有一行代表在Global.asax中委托ObjectContext的设置。EntityUnitOfWorkFactory.SetObjectContext(()=>newMyObjectContext());在网页代码隐藏... 查看详情

具有资源的通用静态库

】具有资源的通用静态库【英文标题】:Universalstaticlibrarywithresources【发布时间】:2013-12-1710:55:02【问题描述】:是否可以使用资源(如图像和xib文件)创建通用静态库。我创建了包含图像和xib文件的静态库,它运行良好。但我... 查看详情

每个实体的通用存储库还是特定存储库?

】每个实体的通用存储库还是特定存储库?【英文标题】:GenericRepositoryorSpecificRepositoryforeachentity?【发布时间】:2019-01-1704:16:24【问题描述】:背景在我工作的公司,我被要求更新旧的MVC应用程序并为SQL数据库实现存储库模式。... 查看详情

Entity Framework 6 异步操作和 TranscationScope

】EntityFramework6异步操作和TranscationScope【英文标题】:EntityFramework6asyncoperationsandTranscationScope【发布时间】:2015-03-2321:39:53【问题描述】:我在***上搜索但找不到类似的问题,如果已经有请指出。我试图实现一个具有同步和异步... 查看详情

csharpef的通用存储库(代码片段)

查看详情

存储库模式和聚合根模式和实体框架

...体框架【英文标题】:RepositoryPatternandaggregaterootpatternandEntityFramework【发布时间】:2013-02-1016:06:27【问题描述】:我正在根据存储库模式、聚合根和工作单元来构建我的应用程序。我正在使用EntityFramework5作为ORM。我不知道如何继... 查看详情

没有 LINQ 扩展的 NHibernate 通用存储库?

】没有LINQ扩展的NHibernate通用存储库?【英文标题】:NHibernategenericrepositorywithoutLINQextension?【发布时间】:2013-11-0412:55:12【问题描述】:我正在寻找几天前的答案,但没有结果。我正在尝试使用NHibernate为通用存储库实现IRepository... 查看详情

csharp存储库模式的通用实现(代码片段)

查看详情

Xamarin 项目中 SQLite-Net 的通用存储库

】Xamarin项目中SQLite-Net的通用存储库【英文标题】:GenericRepositoryforSQLite-NetinXamarinProject【发布时间】:2015-05-1700:10:48【问题描述】:我想知道是否有一种方法可以为我的Xamarin项目编写通用存储库,而不是为我的对象中的每个实... 查看详情

使用 EF 4.1 的通用存储库有啥意义

】使用EF4.1的通用存储库有啥意义【英文标题】:GenericRepositoryWithEF4.1whatisthepoint使用EF4.1的通用存储库有什么意义【发布时间】:2011-08-0307:15:12【问题描述】:当我深入研究DbContext、DbSet和相关接口时,我想知道为什么您需要围... 查看详情

Ninject + Bind 通用存储库

】Ninject+Bind通用存储库【英文标题】:Ninject+Bindgenericrepository【发布时间】:2011-05-2105:00:34【问题描述】:我正在尝试将通用IRepository接口绑定到我的通用存储库-但是它总是返回null?我尝试过各种方法,例如:Bind(typeof(IRepository&... 查看详情

EntityFramework 模型的通用 Getter

】EntityFramework模型的通用Getter【英文标题】:GenericGetterforEntityFrameworkmodels【发布时间】:2017-02-0100:29:53【问题描述】:使用EntityFrameworkv4,我想在C#中为我的模型类创建一个通用getter。我不知道这是否可能以及如何实现。我面临... 查看详情