我正在寻找一个大型项目,该项目将收集有关产品的信息。当前应用程序使用CSLA作为其框架(传统的aspx形式)。
我想将应用程序迁移/开发到.net core 2.1。我有从事MVC的经验(4年以上),并且最近接触过.net内核。
我想使用EF Core来调用现有的存储过程。我正在研究使用工作单元通用存储库设计模式。我以前使用过存储库模式,发现它非常有用。
作为当前过程中存在的功能的一部分,它包含一个Master表和一个Edits表结构格式。当某人编辑产品时,新行将插入到“编辑”表中。一旦获得管理员批准,它就会在主表中插入/更新当前行。
.net core 2.1内的其他开发人员是否已使用“工作单元/通用存储库模式”?
您遇到了什么问题? 我的目标是生产高性能,高效率的驱动应用程序。
欢迎其他任何想法和建议。谢谢。
答案 0 :(得分:4)
就我个人而言,我使用工作单元来减少很多依赖注入。我可以有一个数据库工作单元,一旦我使用依赖注入在该工作单元中注入数据库上下文,就不需要在要使用它们的地方注入每个模型存储库,而只需从数据库中访问存储库即可。工作单元。这也有助于我仅在需要使用特定方法时才实例化存储库。
public interface IDatabaseUnitOfWork
{
DbContext DatabaseContext { get; }
Task<bool> Save();
IBaseRepository<UserAccount> UserAccountRepository { get; }
}
public class DatabaseUnitOfWork : IDatabaseUnitOfWork
{
private IBaseRepository<UserAccount> _userAccountRepository;
public DatabaseUnitOfWork(DbContext databaseContext)
{
DatabaseContext = databaseContext;
}
public DbContext DatabaseContext { get; private set; }
public async Task<bool> Save()
{
try
{
int _save = await DatabaseContext.SaveChangesAsync();
return await Task.FromResult(true);
}
catch (System.Exception e)
{
return await Task.FromResult(false);
}
}
public IBaseRepository<UserAccount> UserAccountRepository
{
get
{
if (_userAccountRepository == null)
{
_userAccountRepository = new BaseRepository<UserAccount>(DatabaseContext);
}
return _userAccountRepository;
}
}
}
然后
services.TryAddSingleton<IDatabaseUnitOfWork, DatabaseUnitOfWork>();
services.TryAddSingleton<IServiceUnitOfWork, ServiceUnitOfWork>();
最后
public class DemoClass
{
private IServiceUnitOfWork _serviceUnitOfWork;
public DemoClass(IServiceUnitOfWork serviceUnitOfWork)
{
_serviceUnitOfWork = serviceUnitOfWork;
}
Public bool CreateUserAccount(UserAccount userAccount){
await _serviceUnitOfWork.UserAccountRepository.Add(userAccount);
return await _serviceUnitOfWork.Save();
}
----
}
更新
通用库
public interface IBaseRepository<T> where T : class
{
Task<bool> Add(T entity);
Task<List<T>> GetAll();
Task<List<T>> GetAll(params Expression<Func<T, object>>[] includes);
Task<List<T>> SearchBy(Expression<Func<T, bool>> searchBy, params Expression<Func<T, object>>[] includes);
Task<T> FindBy(Expression<Func<T, bool>> predicate, params Expression<Func<T, object>>[] includes);
Task<bool> Update(T entity);
Task<bool> Delete(Expression<Func<T, bool>> identity, params Expression<Func<T, object>>[] includes);
Task<bool> Delete(T entity);
}
public class BaseRepository<T> : IBaseRepository<T> where T : class
{
private DbContext _ctx;
public BaseRepository(DbContext context)
{
_ctx = context;
}
public virtual async Task<bool> Add(T entity)
{
try
{
_ctx.Set<T>().Add(entity);
return await Task.FromResult(true);
}
catch (Exception e)
{
return await Task.FromResult(false);
}
}
public virtual async Task<List<T>> GetAll()
{
return _ctx.Set<T>().ToList();
}
public virtual async Task<List<T>> GetAll(params Expression<Func<T, object>>[] includes)
{
var result = _ctx.Set<T>().Where(i => true);
foreach (var includeExpression in includes)
result = result.Include(includeExpression);
return await result.ToListAsync();
}
public virtual async Task<List<T>> SearchBy(Expression<Func<T, bool>> searchBy, params Expression<Func<T, object>>[] includes)
{
var result = _ctx.Set<T>().Where(searchBy);
foreach (var includeExpression in includes)
result = result.Include(includeExpression);
return await result.ToListAsync();
}
/// <summary>
/// Finds by predicate.
/// http://appetere.com/post/passing-include-statements-into-a-repository
/// </summary>
/// <param name="predicate">The predicate.</param>
/// <param name="includes">The includes.</param>
/// <returns></returns>
public virtual async Task<T> FindBy(Expression<Func<T, bool>> predicate, params Expression<Func<T, object>>[] includes)
{
var result = _ctx.Set<T>().Where(predicate);
foreach (var includeExpression in includes)
result = result.Include(includeExpression);
return await result.FirstOrDefaultAsync();
}
public virtual async Task<bool> Update(T entity)
{
try
{
_ctx.Set<T>().Attach(entity);
_ctx.Entry(entity).State = EntityState.Modified;
return await Task.FromResult(true);
}
catch (Exception e)
{
return await Task.FromResult(false);
}
}
public virtual async Task<bool> Delete(Expression<Func<T, bool>> identity, params Expression<Func<T, object>>[] includes)
{
var results = _ctx.Set<T>().Where(identity);
foreach (var includeExpression in includes)
results = results.Include(includeExpression);
try
{
_ctx.Set<T>().RemoveRange(results);
return await Task.FromResult(true);
}
catch (Exception e)
{
return await Task.FromResult(false);
}
}
public virtual async Task<bool> Delete(T entity)
{
_ctx.Set<T>().Remove(entity);
return await Task.FromResult(true);
}
}
扩展基本存储库(例如 DeleteAllAccounts )
public interface IUserAccountRepository : IBaseRepository<UserAccount>
{
Task DeleteAllAccounts();
}
public class UserAccountRepository : BaseRepository<UserAccount>, IUserAccountRepository
{
private DbContext _databaseContext;
public UserAccountRepository(DbContext databaseContext) : base(databaseContext)
{
_databaseContext = databaseContext;
}
public async Task DeleteAllAccounts()
{
......
}
}
因此,您可以使用 _userAccountRepository = new BaseRepository<UserAccount>(DatabaseContext);
_userAccountRepository = new UserAccountRepository(DatabaseContext);
答案 1 :(得分:1)
我要使用经典的“取决于”。本质上DbSet<>
是一个存储库,而DbContext
是一个工作单元。但这并不意味着您不能在更高的抽象级别上使用存储库模式或工作单元模式。
我的建议是直到需要时才使用它。我在EF Core中使用了单元或工作模式,发现它在您使用多个DbContext
或多个数据库提供程序的情况下非常有用。我还没有找到其他可以使用它的实例。
我倾向于从不使用通用存储库,因为我更喜欢封装查询,并将其排除在Controller
或Pages
之外。
已更新为回答以下评论:
这是一个很好的问题,不是一个容易回答的问题,而且肯定不在StackOverflow.com的范围内,因为工艺通常被认为是观点。可以直接交换与代码技巧https://softwareengineering.stackexchange.com相关的问题。
不过,我要说的是,我至少对这个问题感到非常兴奋。
我个人的建议是推荐“域驱动设计”。关于该主题,有很多免费资源,但是直接来源是Eric Evans的书。
从本质上讲,您的业务逻辑是核心,所有依赖关系都向内指向。因此,即使是“服务层”也不会包含您的业务逻辑。