Does anyone have a very complete example generic repository for EF 6.1?

后端 未结 3 1387
囚心锁ツ
囚心锁ツ 2020-12-25 08:21

I have my own repository that is as follows. However this does not take into account some of the new features such as the range features. Does anyone have a repository that

3条回答
  •  忘掉有多难
    2020-12-25 09:01

    You don't need a generic repository. DbContext already is a generic repository. Try this out:

    public class EntityDbContext : DbContext, IWriteEntities
    {
        public IQueryable EagerLoad(IQueryable query,
            Expression> expression)
        {
            // Include will eager load data into the query
            if (query != null && expression != null)
                query = query.Include(expression);
            return query;
        }
    
        public IQueryable Query()
        {
            // AsNoTracking returns entities that are not attached to the DbContext
            return Set().AsNoTracking();
        }
    
        public TEntity Get(object firstKeyValue, params object[] otherKeyValues)
        {
            if (firstKeyValue == null) throw new ArgumentNullException("firstKeyValue");
            var keyValues = new List { firstKeyValue };
            if (otherKeyValues != null) keyValues.AddRange(otherKeyValues);
            return Set().Find(keyValues.ToArray());
        }
    
        public Task GetAsync(object firstKeyValue, params object[] otherKeyValues)
        {
            if (firstKeyValue == null) throw new ArgumentNullException("firstKeyValue");
            var keyValues = new List { firstKeyValue };
            if (otherKeyValues != null) keyValues.AddRange(otherKeyValues);
            return Set().FindAsync(keyValues.ToArray());
        }
    
        public IQueryable Get()
        {
            return Set();
        }
    
        public void Create(TEntity entity)
        {
            if (Entry(entity).State == EntityState.Detached)
                Set().Add(entity);
        }
    
        public void Update(TEntity entity)
        {
            var entry = Entry(entity);
            entry.State = EntityState.Modified;
        }
    
        public void Delete(TEntity entity)
        {
            if (Entry(entity).State != EntityState.Deleted)
                Set().Remove(entity);
        }
    
        public void Reload(TEntity entity)
        {
            Entry(entity).Reload();
        }
    
        public Task ReloadAsync(TEntity entity)
        {
            return Entry(entity).ReloadAsync();
        }
    
        public void DiscardChanges()
        {
            foreach (var entry in ChangeTracker.Entries().Where(x => x != null))
            {
                switch (entry.State)
                {
                    case EntityState.Added:
                        entry.State = EntityState.Detached;
                        break;
                    case EntityState.Modified:
                        entry.State = EntityState.Unchanged;
                        break;
                    case EntityState.Deleted:
                        entry.Reload();
                        break;
                }
            }
        }
    
        public Task DiscardChangesAsync()
        {
            var reloadTasks = new List();
            foreach (var entry in ChangeTracker.Entries().Where(x => x != null))
            {
                switch (entry.State)
                {
                    case EntityState.Added:
                        entry.State = EntityState.Detached;
                        break;
                    case EntityState.Modified:
                        entry.State = EntityState.Unchanged;
                        break;
                    case EntityState.Deleted:
                        reloadTasks.Add(entry.ReloadAsync());
                        break;
                }
            }
            return Task.WhenAll(reloadTasks);
        }
    }
    
    
    

    ... and the interfaces are merely a formality if you need to separate UoW from queries from commands:

    public interface IUnitOfWork
    {
        int SaveChanges();
        Task SaveChangesAsync();
        Task DiscardChangesAsync();
        void DiscardChanges();
    }
    
    public interface IReadEntities
    {
        IQueryable Query();
    
        IQueryable EagerLoad(IQueryable query, 
            Expression> expression);
    }
    
    public interface IWriteEntities : IUnitOfWork, IReadEntities
    {
        TEntity Get(object firstKeyValue, params object[] otherKeyValues);
        Task GetAsync(object firstKeyValue,
            params object[] otherKeyValues);
        IQueryable Get();
        void Create(TEntity entity);
        void Delete(TEntity entity);
        void Update(TEntity entity);
        void Reload(TEntity entity);
        Task ReloadAsync(TEntity entity);
    }
    

    With this, your interface doesn't need to be generic because the methods are generic.

    private readonly IWriteEntities _entities;
    ...
    _entities.Get(keyA);
    await _entities.GetAsync(keyB);
    _entities.Get.Where(...
    var results = await _entities.Query().SingleOrDefaultAsync(...
    

    etc. You just saved 3 unnecessary generic repository dependencies in the code above. One interface can handle all 4 of the entitiy types.

    提交回复
    热议问题