using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Text; using System.Threading; using System.Threading.Tasks; using Microsoft.EntityFrameworkCore; using PlixP.Extentions; using PlixP.Models; using PlixP.Repositories.Contracts; namespace PlixP.Repositories { public class BaseRepository : IBaseRepository where T : Entity { protected readonly PlixContext DbContext; public DbSet Entities { get; } public virtual IQueryable Table => Entities.Where(e => e.IsRemoved == false); public virtual IQueryable TableNoTracking => Entities.AsNoTracking().Where(e => e.IsRemoved == false); public BaseRepository(PlixContext dbContext) { DbContext = dbContext; Entities = DbContext.Set(); // City => Cities } #region Async Method public virtual async Task GetByIdAsync(CancellationToken cancellationToken, params object[] ids) { var entity = await Entities.FindAsync(ids, cancellationToken); DbContext.Entry(entity).State = EntityState.Detached; return entity; } public virtual async Task AddAsync(T entity, CancellationToken cancellationToken, bool saveNow = true) { Assert.NotNull(entity, nameof(entity)); entity.CreationDate = DateTime.Now; await Entities.AddAsync(entity, cancellationToken).ConfigureAwait(false); if (saveNow) await DbContext.SaveChangesAsync(cancellationToken).ConfigureAwait(false); } public virtual async Task AddRangeAsync(IEnumerable entities, CancellationToken cancellationToken, bool saveNow = true) { Assert.NotNull(entities, nameof(entities)); await Entities.AddRangeAsync(entities, cancellationToken).ConfigureAwait(false); if (saveNow) await DbContext.SaveChangesAsync(cancellationToken).ConfigureAwait(false); } public virtual async Task UpdateAsync(T entity, CancellationToken cancellationToken, bool saveNow = true) { Assert.NotNull(entity, nameof(entity)); DbContext.Entry(entity).State = EntityState.Detached; await DbContext.SaveChangesAsync(cancellationToken); //DbContext.Entry(entity).State = EntityState.Modified; DbContext.Update(entity); //DbContext.Entry(entity).CurrentValues.SetValues(entity); if (saveNow) await DbContext.SaveChangesAsync(cancellationToken); } public virtual async Task UpdateRangeAsync(IEnumerable entities, CancellationToken cancellationToken, bool saveNow = true) { Assert.NotNull(entities, nameof(entities)); Entities.UpdateRange(entities); if (saveNow) await DbContext.SaveChangesAsync(cancellationToken); } public virtual async Task DeleteAsync(T entity, CancellationToken cancellationToken, bool saveNow = true) { Assert.NotNull(entity, nameof(entity)); entity.IsRemoved = true; Entities.Update(entity); if (saveNow) await DbContext.SaveChangesAsync(cancellationToken); } public async Task HardDeleteAsync(T entity, CancellationToken cancellationToken, bool saveNow = true) { Assert.NotNull(entity, nameof(entity)); Entities.Remove(entity); if (saveNow) await DbContext.SaveChangesAsync(cancellationToken); } public virtual async Task DeleteRangeAsync(IEnumerable entities, CancellationToken cancellationToken, bool saveNow = true) { Assert.NotNull(entities, nameof(entities)); foreach (var apiEntity in entities) { apiEntity.IsRemoved = true; Entities.Update(apiEntity); } if (saveNow) await DbContext.SaveChangesAsync(cancellationToken); } #endregion #region Sync Methods public virtual T GetById(params object[] ids) { var ent = Entities.Find(ids); Detach(ent); return ent; } public virtual void Add(T entity, bool saveNow = true) { Assert.NotNull(entity, nameof(entity)); Entities.Add(entity); if (saveNow) DbContext.SaveChanges(); } public virtual void AddRange(IEnumerable entities, bool saveNow = true) { Assert.NotNull(entities, nameof(entities)); Entities.AddRange(entities); if (saveNow) DbContext.SaveChanges(); } public virtual void Update(T entity, bool saveNow = true) { Assert.NotNull(entity, nameof(entity)); Detach(entity); Entities.Update(entity); DbContext.SaveChanges(); } public virtual void UpdateRange(IEnumerable entities, bool saveNow = true) { Assert.NotNull(entities, nameof(entities)); Entities.UpdateRange(entities); if (saveNow) DbContext.SaveChanges(); } public virtual void Delete(T entity, bool saveNow = true) { Assert.NotNull(entity, nameof(entity)); Entities.Remove(entity); if (saveNow) DbContext.SaveChanges(); } public virtual void DeleteRange(IEnumerable entities, bool saveNow = true) { Assert.NotNull(entities, nameof(entities)); Entities.RemoveRange(entities); if (saveNow) DbContext.SaveChanges(); } #endregion #region Attach & Detach public virtual void Detach(T entity) { Assert.NotNull(entity, nameof(entity)); var entry = DbContext.Entry(entity); if (entry != null) entry.State = EntityState.Detached; } public virtual void Attach(T entity) { Assert.NotNull(entity, nameof(entity)); if (DbContext.Entry(entity).State == EntityState.Detached) Entities.Attach(entity); } #endregion #region Explicit Loading public virtual async Task LoadCollectionAsync(T entity, Expression>> collectionProperty, CancellationToken cancellationToken) where TProperty : class { Attach(entity); var collection = DbContext.Entry(entity).Collection(collectionProperty); if (!collection.IsLoaded) await collection.LoadAsync(cancellationToken).ConfigureAwait(false); } public virtual void LoadCollection(T entity, Expression>> collectionProperty) where TProperty : class { Attach(entity); var collection = DbContext.Entry(entity).Collection(collectionProperty); if (!collection.IsLoaded) collection.Load(); } public virtual async Task LoadReferenceAsync(T entity, Expression> referenceProperty, CancellationToken cancellationToken) where TProperty : class { Attach(entity); var reference = DbContext.Entry(entity).Reference(referenceProperty); if (!reference.IsLoaded) await reference.LoadAsync(cancellationToken).ConfigureAwait(false); } public virtual void LoadReference(T entity, Expression> referenceProperty) where TProperty : class { Attach(entity); var reference = DbContext.Entry(entity).Reference(referenceProperty); if (!reference.IsLoaded) reference.Load(); } #endregion } }