У кого-нибудь есть очень полный пример универсального репозитория для 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);
}
}
}
3 ответов
вы можете добавить новые функции, как это:
public virtual void AddRange(IEnumerable<T> entities)
{
DbContext.Set<T>().AddRange(entities);
}
public virtual void RemoveRange(IEnumerable<T> entities)
{
DbContext.Set<T>().RemoveRange(entities);
}
вам не нужен общий репозиторий. DbContext, который уже is общий репозиторий. Попробуйте это:
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(...
etc. Вы только что сохранили 3 ненужные зависимости универсального репозитория в приведенном выше коде. Один интерфейс может обрабатывать все 4 типа entitiy.
посмотри общая единица работы и репозитории Framework. Вы можете загрузить весь проект репозитория, изменить код, чтобы включить 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
}
});
надеюсь, что это поможет.