多年來,我一直在我的專案中使用 EF 核心,沒有存盤庫層,現在我決定為我的一個非常大的專案實施存盤庫模式。我們擁有 30 多個物體模型和大量 API 端點。
問題是,每個端點從資料庫中回傳由前端需求格式化的必要資料。有時我們只想要一個物體的串列,有時我們想要包含一些相關資料的同一個串列,有時使用一些 SQL 聚合函式來進行一些計算。
我們只是在每個端點中直接使用 DBContext 來執行我們需要的查詢,但是在實作存盤庫時,我們面臨一個作業障礙,即撰寫幾種方法來獲取不同格式的資料以滿足我們的需求。不僅是基本的 CRUD 和一些更多的操作。
我的問題是,這真的是如何完成的(根據需要創建盡可能多的方法)或者是否有任何最佳實踐?是否有某種方式“重寫” DBContext 以便我可以使用運算式并將其變為通用以避免創建如此馬赫的方法?
非常感謝!
uj5u.com熱心網友回復:
分享我的實際 BaseRepo
public class BaseRepository<TEntity> : IBaseRepository<TEntity> where TEntity : class
{
internal ApplicationDbContext Context;
internal DbSet<TEntity> dbSet;
public BaseRepository(ApplicationDbContext context)
{
this.Context = context;
this.dbSet = context.Set<TEntity>();
}
public virtual async Task AddAsync(TEntity entity)
{
await dbSet.AddAsync(entity);
await SaveAsync();
}
public virtual async Task AddRangeAsync(IEnumerable<TEntity> entities)
{
await dbSet.AddRangeAsync(entities);
await SaveAsync();
}
public virtual async Task<IEnumerable<TEntity>> GetAllAsync()
{
return await dbSet.ToListAsync();
}
public virtual async Task<IEnumerable<TEntity>> GetAsync(Expression<Func<TEntity, bool>> filter = null, Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null, string includeProperties = "")
{
IQueryable<TEntity> query = dbSet;
if (filter != null)
query = query.Where(filter);
foreach (var includeProperty in includeProperties.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
{
query = query.Include(includeProperty);
}
if (orderBy != null)
return await orderBy(query).ToListAsync();
else
return await query.ToListAsync();
}
public virtual async Task<TEntity> GetByIdAsync(int? id)
{
return await dbSet.FindAsync(id);
}
public async Task Remove(TEntity entity)
{
dbSet.Remove(entity);
await SaveAsync();
}
public async Task RemoveRange(IEnumerable<TEntity> entities)
{
dbSet.RemoveRange(entities);
await SaveAsync();
}
public virtual async Task<TEntity> SingleOrDefaultAsync(Expression<Func<TEntity, bool>> predicate)
{
return await dbSet.SingleOrDefaultAsync(predicate);
}
public virtual async Task Update(TEntity entityToUpdate)
{
dbSet.Attach(entityToUpdate);
Context.Entry(entityToUpdate).State = EntityState.Modified;
await SaveAsync();
}
public virtual async Task UpdateRange(IEnumerable<TEntity> entitiesToUpdate)
{
dbSet.AttachRange(entitiesToUpdate);
Context.Entry(entitiesToUpdate).State = EntityState.Modified;
await SaveAsync();
}
public async Task SaveAsync()
{
await Context.SaveChangesAsync();
}
public virtual async Task AddUpdateOrDeleteRange(IEnumerable<TEntity> entitiesToAddOrUpdate)
{
await Context.BulkInsertOrUpdateOrDeleteAsync<TEntity>(entitiesToAddOrUpdate.ToList(), new BulkConfig { SetOutputIdentity = false });
await SaveAsync();
}
public virtual async Task AddOrUpdateRange(IEnumerable<TEntity> entitiesToAddOrUpdate)
{
await Context.BulkInsertOrUpdateAsync<TEntity>(entitiesToAddOrUpdate.ToList(), new BulkConfig { SetOutputIdentity = false });
await SaveAsync();
}
}
批量是 EFCore.BulkExtensions 的擴展;
作業單元
public class UnitOfWork : IUnitOfWork, IDisposable, IAsyncDisposable
{
private readonly ApplicationDbContext _context;
private ExampleRepository _exampleRepository;
IDisposable _disposableResource = new MemoryStream();
IAsyncDisposable _asyncDisposableResource = new MemoryStream();
public UnitOfWork(ApplicationDbContext context)
{
_context = context;
}
public IExampleRepository ExampleRepository=> _exampleRepository = _exampleRepository ?? new ExampleRepository(_context);
public async Task<int> CommitAsync()
{
return await _context.SaveChangesAsync();
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
public async ValueTask DisposeAsync()
{
await DisposeAsyncCore();
Dispose(disposing: false);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
_disposableResource?.Dispose();
(_asyncDisposableResource as IDisposable)?.Dispose();
}
_disposableResource = null;
_asyncDisposableResource = null;
}
protected virtual async ValueTask DisposeAsyncCore()
{
if (_asyncDisposableResource is not null)
{
await _asyncDisposableResource.DisposeAsync().ConfigureAwait(false);
}
if (_disposableResource is IAsyncDisposable disposable)
{
await disposable.DisposeAsync().ConfigureAwait(false);
}
else
{
_disposableResource?.Dispose();
}
_asyncDisposableResource = null;
_disposableResource = null;
}
}
應用程式背景關系:
public class ApplicationDbContext : DbContext
{
public DbSet<Example> Examples { get; set; }
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options) { }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
}
}
希望對你有幫助!
uj5u.com熱心網友回復:
創建一個基礎 Crud 類,如下所示:
public class BaseRepository<TEntity> where TEntity : class, new()
然后創建一組標準方法:
public virtual TEntity Get(Expression<Func<TEntity, bool>> predicate)
{
using (var scope = ScopeFactory.CreateScope())
{
var Context = scope.ServiceProvider.GetRequiredService<ubContext>();
var item = Context.Set<TEntity>().FirstOrDefault(predicate);
return item;
}
}
public List<TEntity> GetList(Expression<Func<TEntity, bool>> predicate)
{
using (var scope = ScopeFactory.CreateScope())
{
var Context = scope.ServiceProvider.GetRequiredService<ubContext>();
var item = Context.Set<TEntity>().Where(predicate).AsNoTracking().ToList();
return item;
}
}
public IQueryable GetListQueryable<TContext>(Expression<Func<TEntity, bool>> predicate)
{
using (var scope = ScopeFactory.CreateScope())
{
var Context = scope.ServiceProvider.GetRequiredService<ubContext>();
var item = Context.Set<TEntity>().Where(predicate);
return item;
}
}
您還可以進行插入或更新:
public virtual void Update(TEntity input, Expression<Func<TEntity, bool>> predicate)
{
using (var scope = ScopeFactory.CreateScope())
{
var Context = scope.ServiceProvider.GetRequiredService<ubContext>();
if (input == null)
return;
var existing = Context.Set<TEntity>().FirstOrDefault(predicate);
if (existing != null)
{
Context.Entry(existing).CurrentValues.SetValues(input);
Context.SaveChanges();
}
}
}
public virtual void Insert(TEntity input)
{
using var scope = ScopeFactory.CreateScope();
var context = scope.ServiceProvider.GetRequiredService<ubContext>();
context.Set<TEntity>().Add(input);
context.SaveChanges();
}
現在,如果您需要根據多載或一些“怪異”的處理來做一些特定的事情,您可以創建一個繼承自這個基類的類。(但使用表的特定名稱作為 TEntity)現在您可以使用多型性來更改行為或創建您喜歡的新行為。
此外,您可能不需要采用范圍方法來處理請求,這只是從我已經制作的現有代碼庫中“勾勒”出來的,它確實有它作為要求。
如果這沒有意義,請告訴我,我會從專案中為您提供更多代碼。
uj5u.com熱心網友回復:
public abstract class DBAccess
{
private readonly DbContext _db;
public DBAccess(DbContext db)
{
_db = db;
}
protected virtual IQueryable<T> Get<T>() where T : class
{
return _db.Set<T>().AsQueryable();
}
}
然后你可以像這樣使用它:
private ApplicationUser GetUser(int id)
{
return _dbAccess.Get<ApplicationUser>().Where(w => w.Id == id).FirstOrDefault();
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/519417.html
