Created
June 27, 2018 12:07
-
-
Save MongkonEiadon/ecc827969b0a522f38a8c69a9feb23b0 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class EfCoreRepositoryBase<TEntity> : EfCoreRepositoryBase<TEntity, Guid>, IRepository<TEntity> | |
where TEntity : class, IEntity | |
{ | |
public EfCoreRepositoryBase(AiOptionContext dbDbContext) : base(dbDbContext) | |
{ | |
} | |
} | |
public class EfCoreRepositoryBase<TEntity, TPrimaryKey> : RepositoryBase<TEntity, TPrimaryKey>, IRepositoryWithDbContext | |
where TEntity : class, IEntity<TPrimaryKey> | |
{ | |
private readonly AiOptionContext _dbContext; | |
public virtual DbSet<TEntity> Table => _dbContext.Set<TEntity>(); | |
public EfCoreRepositoryBase(AiOptionContext dbDbContext) | |
{ | |
_dbContext = dbDbContext; | |
} | |
public override IQueryable<TEntity> GetAll() | |
{ | |
return Table.AsQueryable(); | |
} | |
public override TEntity Insert(TEntity entity) | |
{ | |
var newEntity = Table.Add(entity).Entity; | |
_dbContext.SaveChanges(); | |
return newEntity; | |
} | |
public override TEntity Update(TEntity entity) | |
{ | |
AttachIfNot(entity); | |
_dbContext.Entry(entity).State = EntityState.Modified; | |
_dbContext.SaveChanges(); | |
return entity; | |
} | |
public override void Delete(TEntity entity) | |
{ | |
AttachIfNot(entity); | |
Table.Remove(entity); | |
_dbContext.SaveChanges(); | |
} | |
public override void Delete(TPrimaryKey id) | |
{ | |
var entity = GetFromChangeTrackerOrNull(id); | |
if (entity != null) | |
{ | |
Delete(entity); | |
return; | |
} | |
entity = FirstOrDefault(id); | |
if (entity != null) | |
{ | |
Delete(entity); | |
return; | |
} | |
} | |
public DbContext GetDbContext() | |
{ | |
return _dbContext; | |
} | |
protected virtual void AttachIfNot(TEntity entity) | |
{ | |
var entry = _dbContext.ChangeTracker.Entries().FirstOrDefault(ent => ent.Entity == entity); | |
if (entry != null) | |
{ | |
return; | |
} | |
Table.Attach(entity); | |
} | |
private TEntity GetFromChangeTrackerOrNull(TPrimaryKey id) | |
{ | |
var entry = _dbContext.ChangeTracker.Entries() | |
.FirstOrDefault( | |
ent => | |
ent.Entity is TEntity && | |
EqualityComparer<TPrimaryKey>.Default.Equals(id, ((TEntity)ent.Entity).Id) | |
); | |
return entry?.Entity as TEntity; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public interface IRepository<TEntity> : IRepository<TEntity, Guid> | |
where TEntity : class, IEntity | |
{ | |
} | |
public interface IRepository<TEntity, TPrimaryKey> | |
where TEntity : class, IEntity<TPrimaryKey> | |
{ | |
#region Select | |
/// <summary> | |
/// Used to get a IQueryable that is used to retrieve entities from entire table. | |
/// </summary> | |
/// <returns>IQueryable to be used to select entities from database</returns> | |
IQueryable<TEntity> GetAll(); | |
/// <summary> | |
/// Gets an entity with given primary key. | |
/// </summary> | |
/// <param name="id">Primary key of the entity to get</param> | |
/// <returns>Entity</returns> | |
TEntity Get(TPrimaryKey id); | |
/// <summary> | |
/// Gets an entity with given primary key. | |
/// </summary> | |
/// <param name="id">Primary key of the entity to get</param> | |
/// <returns>Entity</returns> | |
Task<TEntity> GetAsync(TPrimaryKey id); | |
/// <summary> | |
/// Used to get all entities. | |
/// </summary> | |
/// <returns>List of all entities</returns> | |
List<TEntity> GetAllList(); | |
/// <summary> | |
/// Used to get all entities. | |
/// </summary> | |
/// <returns>List of all entities</returns> | |
Task<List<TEntity>> GetAllListAsync(); | |
/// <summary> | |
/// Used to get all entities based on given <paramref name="predicate"/>. | |
/// </summary> | |
/// <param name="predicate">A condition to filter entities</param> | |
/// <returns>List of all entities</returns> | |
List<TEntity> GetAllList(Expression<Func<TEntity, bool>> predicate); | |
/// <summary> | |
/// Used to get all entities based on given <paramref name="predicate"/>. | |
/// </summary> | |
/// <param name="predicate">A condition to filter entities</param> | |
/// <returns>List of all entities</returns> | |
Task<List<TEntity>> GetAllListAsync(Expression<Func<TEntity, bool>> predicate); | |
/// <summary> | |
/// Used to run a query over entire entities. | |
/// if <paramref name="queryMethod"/> finishes IQueryable with ToList, FirstOrDefault etc.. | |
/// </summary> | |
/// <typeparam name="T">Type of return value of this method</typeparam> | |
/// <param name="queryMethod">This method is used to query over entities</param> | |
/// <returns>Query result</returns> | |
T Query<T>(Func<IQueryable<TEntity>, T> queryMethod); | |
/// <summary> | |
/// Gets an entity with given primary key or null if not found. | |
/// </summary> | |
/// <param name="id">Primary key of the entity to get</param> | |
/// <returns>Entity or null</returns> | |
TEntity FirstOrDefault(TPrimaryKey id); | |
/// <summary> | |
/// Gets an entity with given primary key or null if not found. | |
/// </summary> | |
/// <param name="id">Primary key of the entity to get</param> | |
/// <returns>Entity or null</returns> | |
Task<TEntity> FirstOrDefaultAsync(TPrimaryKey id); | |
/// <summary> | |
/// Gets an entity with given given predicate or null if not found. | |
/// </summary> | |
/// <param name="predicate">Predicate to filter entities</param> | |
TEntity FirstOrDefault(Expression<Func<TEntity, bool>> predicate); | |
/// <summary> | |
/// Gets an entity with given given predicate or null if not found. | |
/// </summary> | |
/// <param name="predicate">Predicate to filter entities</param> | |
Task<TEntity> FirstOrDefaultAsync(Expression<Func<TEntity, bool>> predicate); | |
#endregion | |
#region Insert | |
/// <summary> | |
/// Inserts a new entity. | |
/// </summary> | |
/// <param name="entity">Inserted entity</param> | |
TEntity Insert(TEntity entity); | |
/// <summary> | |
/// Inserts a new entity. | |
/// </summary> | |
/// <param name="entity">Inserted entity</param> | |
Task<TEntity> InsertAsync(TEntity entity); | |
/// <summary> | |
/// Inserts a new entity and gets it's Id. | |
/// It may require to save current unit of work | |
/// to be able to retrieve id. | |
/// </summary> | |
/// <param name="entity">Entity</param> | |
/// <returns>Id of the entity</returns> | |
TPrimaryKey InsertAndGetId(TEntity entity); | |
/// <summary> | |
/// Inserts a new entity and gets it's Id. | |
/// It may require to save current unit of work | |
/// to be able to retrieve id. | |
/// </summary> | |
/// <param name="entity">Entity</param> | |
/// <returns>Id of the entity</returns> | |
Task<TPrimaryKey> InsertAndGetIdAsync(TEntity entity); | |
#endregion Insert | |
#region Update | |
/// <summary> | |
/// Updates an existing entity. | |
/// </summary> | |
/// <param name="entity">Entity</param> | |
TEntity Update(TEntity entity); | |
/// <summary> | |
/// Updates an existing entity. | |
/// </summary> | |
/// <param name="entity">Entity</param> | |
Task<TEntity> UpdateAsync(TEntity entity); | |
#endregion Update | |
#region Delete | |
/// <summary> | |
/// Deletes an entity. | |
/// </summary> | |
/// <param name="entity">Entity to be deleted</param> | |
void Delete(TEntity entity); | |
/// <summary> | |
/// Deletes an entity. | |
/// </summary> | |
/// <param name="entity">Entity to be deleted</param> | |
Task DeleteAsync(TEntity entity); | |
/// <summary> | |
/// Deletes an entity by primary key. | |
/// </summary> | |
/// <param name="id">Primary key of the entity</param> | |
void Delete(TPrimaryKey id); | |
/// <summary> | |
/// Deletes an entity by primary key. | |
/// </summary> | |
/// <param name="id">Primary key of the entity</param> | |
Task DeleteAsync(TPrimaryKey id); | |
/// <summary> | |
/// Deletes many entities by function. | |
/// Notice that: All entities fits to given predicate are retrieved and deleted. | |
/// This may cause major performance problems if there are too many entities with | |
/// given predicate. | |
/// </summary> | |
/// <param name="predicate">A condition to filter entities</param> | |
void Delete(Expression<Func<TEntity, bool>> predicate); | |
/// <summary> | |
/// Deletes many entities by function. | |
/// Notice that: All entities fits to given predicate are retrieved and deleted. | |
/// This may cause major performance problems if there are too many entities with | |
/// given predicate. | |
/// </summary> | |
/// <param name="predicate">A condition to filter entities</param> | |
Task DeleteAsync(Expression<Func<TEntity, bool>> predicate); | |
#endregion | |
#region Aggregates | |
/// <summary> | |
/// Gets count of all entities in this repository. | |
/// </summary> | |
/// <returns>Count of entities</returns> | |
int Count(); | |
/// <summary> | |
/// Gets count of all entities in this repository. | |
/// </summary> | |
/// <returns>Count of entities</returns> | |
Task<int> CountAsync(); | |
/// <summary> | |
/// Gets count of all entities in this repository based on given <paramref name="predicate"/>. | |
/// </summary> | |
/// <param name="predicate">A method to filter count</param> | |
/// <returns>Count of entities</returns> | |
int Count(Expression<Func<TEntity, bool>> predicate); | |
/// <summary> | |
/// Gets count of all entities in this repository based on given <paramref name="predicate"/>. | |
/// </summary> | |
/// <param name="predicate">A method to filter count</param> | |
/// <returns>Count of entities</returns> | |
Task<int> CountAsync(Expression<Func<TEntity, bool>> predicate); | |
/// <summary> | |
/// Gets count of all entities in this repository (use if expected return value is greather than <see cref="int.MaxValue"/>. | |
/// </summary> | |
/// <returns>Count of entities</returns> | |
long LongCount(); | |
/// <summary> | |
/// Gets count of all entities in this repository (use if expected return value is greather than <see cref="int.MaxValue"/>. | |
/// </summary> | |
/// <returns>Count of entities</returns> | |
Task<long> LongCountAsync(); | |
/// <summary> | |
/// Gets count of all entities in this repository based on given <paramref name="predicate"/> | |
/// (use this overload if expected return value is greather than <see cref="int.MaxValue"/>). | |
/// </summary> | |
/// <param name="predicate">A method to filter count</param> | |
/// <returns>Count of entities</returns> | |
long LongCount(Expression<Func<TEntity, bool>> predicate); | |
/// <summary> | |
/// Gets count of all entities in this repository based on given <paramref name="predicate"/> | |
/// (use this overload if expected return value is greather than <see cref="int.MaxValue"/>). | |
/// </summary> | |
/// <param name="predicate">A method to filter count</param> | |
/// <returns>Count of entities</returns> | |
Task<long> LongCountAsync(Expression<Func<TEntity, bool>> predicate); | |
#endregion | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
builder.RegisterType<AiOptionContext>().As<DbContext>() | |
.Named<DbContext>("iqoptioncontext") | |
.SingleInstance() | |
.AsImplementedInterfaces(); | |
builder.RegisterType(typeof(EfCoreRepositoryBase<>)).As<IRepositoryWithDbContext>().InstancePerDependency(); | |
builder.RegisterType(typeof(EfCoreRepositoryBase<,>)).As<IRepositoryWithDbContext>().InstancePerDependency(); | |
builder.RegisterGeneric(typeof(EfCoreRepositoryBase<,>)) | |
.As(typeof(IRepository<,>)) | |
.WithParameters(new[] | |
{ | |
new ResolvedParameter( | |
(p, ctx) => p.ParameterType == typeof(AiOptionContext), | |
(p, ctx) => ctx.ResolveNamed<DbContext>("iqoptioncontext")) | |
}).InstancePerDependency(); | |
builder.RegisterGeneric(typeof(EfCoreRepositoryBase<>)).As(typeof(IRepository<>)) | |
.WithParameters(new[] | |
{ | |
new ResolvedParameter( | |
(p, ctx) => p.ParameterType == typeof(AiOptionContext), | |
(p, ctx) => ctx.ResolveNamed<DbContext>("iqoptioncontext")) | |
}).InstancePerDependency(); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public abstract class RepositoryBase<TEntity, TPrimaryKey> : IRepository<TEntity, TPrimaryKey> | |
where TEntity : class, IEntity<TPrimaryKey> | |
{ | |
public abstract IQueryable<TEntity> GetAll(); | |
public virtual List<TEntity> GetAllList() | |
{ | |
return GetAll().ToList(); | |
} | |
public virtual Task<List<TEntity>> GetAllListAsync() | |
{ | |
return Task.FromResult(GetAllList()); | |
} | |
public virtual List<TEntity> GetAllList(Expression<Func<TEntity, bool>> predicate) | |
{ | |
return GetAll().Where(predicate).ToList(); | |
} | |
public virtual Task<List<TEntity>> GetAllListAsync(Expression<Func<TEntity, bool>> predicate) | |
{ | |
return Task.FromResult(GetAllList(predicate)); | |
} | |
public virtual T Query<T>(Func<IQueryable<TEntity>, T> queryMethod) | |
{ | |
return queryMethod(GetAll()); | |
} | |
public virtual TEntity Get(TPrimaryKey id) | |
{ | |
var entity = FirstOrDefault(id); | |
return entity; | |
} | |
public virtual async Task<TEntity> GetAsync(TPrimaryKey id) | |
{ | |
var entity = await FirstOrDefaultAsync(id); | |
return entity; | |
} | |
public virtual TEntity FirstOrDefault(TPrimaryKey id) | |
{ | |
return GetAll().FirstOrDefault(CreateEqualityExpressionForId(id)); | |
} | |
public virtual Task<TEntity> FirstOrDefaultAsync(TPrimaryKey id) | |
{ | |
return Task.FromResult(FirstOrDefault(id)); | |
} | |
public virtual TEntity FirstOrDefault(Expression<Func<TEntity, bool>> predicate) | |
{ | |
return GetAll().FirstOrDefault(predicate); | |
} | |
public virtual Task<TEntity> FirstOrDefaultAsync(Expression<Func<TEntity, bool>> predicate) | |
{ | |
return Task.FromResult(FirstOrDefault(predicate)); | |
} | |
public abstract TEntity Insert(TEntity entity); | |
public virtual Task<TEntity> InsertAsync(TEntity entity) | |
{ | |
return Task.FromResult(Insert(entity)); | |
} | |
public virtual TPrimaryKey InsertAndGetId(TEntity entity) | |
{ | |
return Insert(entity).Id; | |
} | |
public virtual Task<TPrimaryKey> InsertAndGetIdAsync(TEntity entity) | |
{ | |
return Task.FromResult(InsertAndGetId(entity)); | |
} | |
public abstract TEntity Update(TEntity entity); | |
public virtual Task<TEntity> UpdateAsync(TEntity entity) | |
{ | |
return Task.FromResult(Update(entity)); | |
} | |
public abstract void Delete(TEntity entity); | |
public virtual Task DeleteAsync(TEntity entity) | |
{ | |
Delete(entity); | |
return Task.FromResult(0); | |
} | |
public abstract void Delete(TPrimaryKey id); | |
public virtual Task DeleteAsync(TPrimaryKey id) | |
{ | |
Delete(id); | |
return Task.FromResult(0); | |
} | |
public virtual void Delete(Expression<Func<TEntity, bool>> predicate) | |
{ | |
foreach (var entity in GetAll().Where(predicate).ToList()) | |
{ | |
Delete(entity); | |
} | |
} | |
public virtual Task DeleteAsync(Expression<Func<TEntity, bool>> predicate) | |
{ | |
Delete(predicate); | |
return Task.FromResult(0); | |
} | |
public virtual int Count() | |
{ | |
return GetAll().Count(); | |
} | |
public virtual Task<int> CountAsync() | |
{ | |
return Task.FromResult(Count()); | |
} | |
public virtual int Count(Expression<Func<TEntity, bool>> predicate) | |
{ | |
return GetAll().Where(predicate).Count(); | |
} | |
public virtual Task<int> CountAsync(Expression<Func<TEntity, bool>> predicate) | |
{ | |
return Task.FromResult(Count(predicate)); | |
} | |
public virtual long LongCount() | |
{ | |
return GetAll().LongCount(); | |
} | |
public virtual Task<long> LongCountAsync() | |
{ | |
return Task.FromResult(LongCount()); | |
} | |
public virtual long LongCount(Expression<Func<TEntity, bool>> predicate) | |
{ | |
return GetAll().Where(predicate).LongCount(); | |
} | |
public virtual Task<long> LongCountAsync(Expression<Func<TEntity, bool>> predicate) | |
{ | |
return Task.FromResult(LongCount(predicate)); | |
} | |
protected static Expression<Func<TEntity, bool>> CreateEqualityExpressionForId(TPrimaryKey id) | |
{ | |
var lambdaParam = Expression.Parameter(typeof(TEntity)); | |
var lambdaBody = Expression.Equal( | |
Expression.PropertyOrField(lambdaParam, "Id"), | |
Expression.Constant(id, typeof(TPrimaryKey)) | |
); | |
return Expression.Lambda<Func<TEntity, bool>>(lambdaBody, lambdaParam); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment