toa*_*ast 5 c# architecture wpf entity-framework
我们目前在WPF应用程序上遇到架构问题.它涉及EntityFramework上下文管理,它实例化一次并在应用程序的整个生命周期中使用.因此,我们最终会遇到缓存问题,实体在加载一次时不会更新.使用该应用程序时,我们的实体已过时.
这是当前架构的架构.
[Export(typeof(OrderViewModel))]
[PartCreationPolicy(CreationPolicy.NonShared)]
public class OrderViewModel : ViewModelBase
{
private readonly IOrderManagementService _orderManagementService;
private readonly IOrderReadOnlyRepository _orderReadOnlyRepository;
[ImportingConstructor]
public OrderViewModel(IOrderManagementService orderManagementService, IOrderReadOnlyRepository orderReadOnlyRepository)
{
_orderManagementService = orderManagementService;
_orderReadOnlyRepository = orderReadOnlyRepository;
}
}
Run Code Online (Sandbox Code Playgroud)
public class OrderManagementService : IOrderManagementService
{
private readonly IUnitOfWork _unitOfWork;
private readonly IOrderManagementBusiness _orderManagementBusiness;
[ImportingConstructor]
public OrderManagementService (IUnitOfWork unitOfWork, IOrderManagementBusiness orderManagementBusiness)
{
_unitOfWork= unitOfWork;
_orderManagementBusiness = orderManagementBusiness;
}
}
Run Code Online (Sandbox Code Playgroud)
public class OrderManagementBusiness : IOrderManagementBusiness
{
private readonly IOrderReadOnlyRepository _orderReadOnlyRepository;
[ImportingConstructor]
public OrderManagementBusiness (IOrderReadOnlyRepository orderReadOnlyRepository)
{
_orderReadOnlyRepository = orderReadOnlyRepository;
}
}
Run Code Online (Sandbox Code Playgroud)
public class OrderReadOnlyRepository : ReadOnlyRepositoryBase<DataModelContainer, Order>, IOrderReadOnlyRepository
{
[ImportingConstructor]
public OrderReadOnlyRepository (IUnitOfWork uow) : base(uow)
{
}
}
Run Code Online (Sandbox Code Playgroud)
public abstract class ReadOnlyRepositoryBase<TContext, TEntity> : IReadOnlyRepository<TEntity>
where TEntity : class, IEntity
where TContext : DbContext
{
protected readonly TContext _context;
protected ReadOnlyRepositoryBase(IUnitOfWork uow)
{
_context = uow.Context;
}
protected DbSet<TEntity> DbSet
{
get { return _context.Set<TEntity>();
}
public virtual IEnumerable<TEntity> GetAll(System.Linq.Expressions.Expression<Func<TEntity, bool>> filter = null, Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null, string includeProperties = "")
{
IQueryable<TEntity> query = DbSet.AsNoTracking();
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 orderBy(query).ToList();
}
return query.ToList();
}
public virtual IQueryable<TEntity> All()
{
return DbSet.AsNoTracking();
}
public virtual IQueryable<TEntity> AllWhere(Expression<Func<TEntity, bool>> predicate)
{
return DbSet.Where(predicate).AsNoTracking();
}
public virtual TEntity Get(Expression<Func<TEntity, bool>> predicate)
{
return DbSet.Where(predicate).AsNoTracking().FirstOrDefault();
}
public virtual TEntity GetById(int id)
{
TEntity find = DbSet.Find(id);
_context.Entry(find).State = System.Data.EntityState.Detached;
return DbSet.Find(id);
}
Run Code Online (Sandbox Code Playgroud)
我们可以看到上下文被赋予构造函数中的存储库.选择方法使用"AsNoTracking()"方法不缓存实体.这是一个暂时的解决方案,从长远来看显然是不可行的.
public class UnitOfWork : IUnitOfWork
{
private DataModelContainer _context;
public UnitOfWork()
: this(new DataModelContainer())
{
}
public UnitOfWork(DataModelContainer context)
{
_context = context;
}
public DataModelContainer Context
{
get { return _context; }
}
public int Save()
{
return _context.SaveChanges();
}
}
Run Code Online (Sandbox Code Playgroud)
在使用MEF的服务的第一个组合期间,UnitOfWork将使用默认构造函数实例化,该构造函数实例化上下文.
为了便于阅读,省略了一些代码.
上下文的生命周期显然是一个问题.知道同一服务方法中的所有调用必须共享相同的上下文.
我们如何考虑修改体系结构以避免出现单个上下文?
随意问的问题 !如果需要,我可以附上一个突出问题的测试项目.
在您的应用程序中只有一个工作单元,但这并不是工作单元的目的。相反,每次“使用数据库”时,您都需要创建一个工作单元。在您的情况下,它UnitOfWork
不应该是 MEF 容器的一部分,但您可以创建一个UnitOfWorkFactory
并从容器中注入它。然后,服务可以UnitOfWork
在每次“必须完成工作”时使用数据库创建一个:
using (var unitOfWork = unitOfWorkFactory.Create()) {
// Do work ...
unitOfWork.Save();
}
Run Code Online (Sandbox Code Playgroud)
我已经修改了,UnitOfWork
所以它实现了IDisposable
。这将允许您处理 EF 上下文,并且还可以回滚事务(如果Save
未调用)。如果您不需要额外的事务处理,您甚至可以摆脱该类UnitOfWork
,因为它只是包装 EF 上下文,而您可以直接将 EF 上下文用作工作单元。
此更改将迫使您修改服务和存储库的结构,但您确实必须这样做,因为您的问题是您有一个在应用程序的整个持续时间内存在的工作单元。