У кого-нибудь есть очень полный пример общего репозитория для EF 6.1?

У меня есть собственный репозиторий, который выглядит следующим образом. Однако это не учитывает некоторые новые функции, такие как функции диапазона. Кто-нибудь имеет репозиторий, который включает в себя все. Я искал это в сети, но ничего, что я могу найти, это последнее. Вот что у меня есть. Я надеюсь на то, что имеет больше и что предлагает IQueryable для многих методов:

namespace Services.Repositories
{
    /// <summary>
    /// The EF-dependent, generic repository for data access
    /// </summary>
    /// <typeparam name="T">Type of entity for this Repository.</typeparam>
    public class GenericRepository<T> : IRepository<T> where T : class
    {
        public GenericRepository(DbContext dbContext)
        {
            if (dbContext == null) 
                throw new ArgumentNullException("An instance of DbContext is required to use this repository", "context");
            DbContext = dbContext;
            DbSet = DbContext.Set<T>();
        }

        protected DbContext DbContext { get; set; }

        protected DbSet<T> DbSet { get; set; }

        public virtual IQueryable<T> Find(Expression<Func<T, bool>> predicate)
        {
            return DbSet.Where<T>(predicate);
        }

        public virtual IQueryable<T> GetAll()
        {
            return DbSet;
        }

        public virtual T GetById(int id)
        {
            //return DbSet.FirstOrDefault(PredicateBuilder.GetByIdPredicate<T>(id));
            return DbSet.Find(id);
        }

        public virtual void Add(T entity)
        {
            DbEntityEntry dbEntityEntry = DbContext.Entry(entity);
            if (dbEntityEntry.State != EntityState.Detached)
            {
                dbEntityEntry.State = EntityState.Added;
            }
            else
            {
                DbSet.Add(entity);
            }
        }

        public virtual void Update(T entity)
        {
            DbEntityEntry dbEntityEntry = DbContext.Entry(entity);
            if (dbEntityEntry.State == EntityState.Detached)
            {
                DbSet.Attach(entity);
            }  
            dbEntityEntry.State = EntityState.Modified;
        }

        public virtual void Delete(T entity)
        {
            DbEntityEntry dbEntityEntry = DbContext.Entry(entity);
            if (dbEntityEntry.State != EntityState.Deleted)
            {
                dbEntityEntry.State = EntityState.Deleted;
            }
            else
            {
                DbSet.Attach(entity);
                DbSet.Remove(entity);
            }
        }

        public virtual void Delete(int id)
        {
            var entity = GetById(id);
            if (entity == null) return; // not found; assume already deleted.
            Delete(entity);
        }
    }
}

Ответ 1

Вы можете добавить новые функции следующим образом:

public virtual void AddRange(IEnumerable<T> entities)
{
    DbContext.Set<T>().AddRange(entities);
}

public virtual void RemoveRange(IEnumerable<T> entities)
{
    DbContext.Set<T>().RemoveRange(entities);
}

Ответ 2

Вам не нужен общий репозиторий. DbContext уже является общим хранилищем. Попробуйте это:

public class EntityDbContext : DbContext, IWriteEntities
{
    public IQueryable<TEntity> EagerLoad<TEntity>(IQueryable<TEntity> query,
        Expression<Func<TEntity, object>> expression)
    {
        // Include will eager load data into the query
        if (query != null && expression != null)
            query = query.Include(expression);
        return query;
    }

    public IQueryable<TEntity> Query<TEntity>()
    {
        // AsNoTracking returns entities that are not attached to the DbContext
        return Set<TEntity>().AsNoTracking();
    }

    public TEntity Get<TEntity>(object firstKeyValue, params object[] otherKeyValues)
    {
        if (firstKeyValue == null) throw new ArgumentNullException("firstKeyValue");
        var keyValues = new List<object> { firstKeyValue };
        if (otherKeyValues != null) keyValues.AddRange(otherKeyValues);
        return Set<TEntity>().Find(keyValues.ToArray());
    }

    public Task<TEntity> GetAsync<TEntity>(object firstKeyValue, params object[] otherKeyValues)
    {
        if (firstKeyValue == null) throw new ArgumentNullException("firstKeyValue");
        var keyValues = new List<object> { firstKeyValue };
        if (otherKeyValues != null) keyValues.AddRange(otherKeyValues);
        return Set<TEntity>().FindAsync(keyValues.ToArray());
    }

    public IQueryable<TEntity> Get<TEntity>()
    {
        return Set<TEntity>();
    }

    public void Create<TEntity>(TEntity entity)
    {
        if (Entry(entity).State == EntityState.Detached)
            Set<TEntity>().Add(entity);
    }

    public void Update<TEntity>(TEntity entity)
    {
        var entry = Entry(entity);
        entry.State = EntityState.Modified;
    }

    public void Delete<TEntity>(TEntity entity)
    {
        if (Entry(entity).State != EntityState.Deleted)
            Set<TEntity>().Remove(entity);
    }

    public void Reload<TEntity>(TEntity entity)
    {
        Entry(entity).Reload();
    }

    public Task ReloadAsync<TEntity>(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<Task>();
        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);
    }
}

... и интерфейсы являются просто формальностью, если вам нужно отделить UoW от запросов от команд:

public interface IUnitOfWork
{
    int SaveChanges();
    Task<int> SaveChangesAsync();
    Task DiscardChangesAsync();
    void DiscardChanges();
}

public interface IReadEntities
{
    IQueryable<TEntity> Query<TEntity>();

    IQueryable<TEntity> EagerLoad<TEntity>(IQueryable<TEntity> query, 
        Expression<Func<TEntity, object>> expression);
}

public interface IWriteEntities : IUnitOfWork, IReadEntities
{
    TEntity Get<TEntity>(object firstKeyValue, params object[] otherKeyValues);
    Task<TEntity> GetAsync<TEntity>(object firstKeyValue,
        params object[] otherKeyValues);
    IQueryable<TEntity> Get<TEntity>();
    void Create<TEntity>(TEntity entity);
    void Delete<TEntity>(TEntity entity);
    void Update<TEntity>(TEntity entity);
    void Reload<TEntity>(TEntity entity);
    Task ReloadAsync<TEntity>(TEntity entity);
}

При этом ваш интерфейс не обязательно должен быть общим, потому что методы являются общими.

private readonly IWriteEntities _entities;
...
_entities.Get<MyEntityA>(keyA);
await _entities.GetAsync<MyEntityB>(keyB);
_entities.Get<MyEntityC>.Where(...
var results = await _entities.Query<MyEntityD>().SingleOrDefaultAsync(...

и т.д.. Вы только что сохранили 3 ненужных общих репозитарных зависимостей в приведенном выше коде. Один интерфейс может обрабатывать все 4 типа entitiy.

Ответ 3

Взгляните на Общие рамки работы и репозитории. Вы можете загрузить весь проект репозитория, изменить код, чтобы включить функции range, реализовать его в своем собственном решении и т.д.

Вот пример его использования в контексте метода контроллера OData/WebAPI, возвращающего DTO, а не объект EF.

            var results = odataQueryOptions.ApplyTo(_uow.Repository<ContentType>()
                .Query()
                .Get()
                .Include(u => u.User)
                .Where(u => u.UserId == userId)
                .OrderBy(o => o.Description)).Cast<ContentType>()
                .Select(x => new ContentTypeDTO()
                {
                    //projection goes here
                    ContentTypeId = x.ContentTypeId,
                    Description = x.Description,
                    UserDTO = new UserDTO 
                    { 
                        UserId = x.UserId,
                        UserName = x.User.UserName
                    }
                });

Надеюсь, что это поможет.