WPF /的EntityFramework上下文生存 [英] WPF / EntityFramework Context Lifetime

查看:165
本文介绍了WPF /的EntityFramework上下文生存的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们目前有一个WPF应用程序架构的问题。它涉及的EntityFramework上下文管理,它的实例化一次和应用程序的整个生命过程中使用。因此,我们结束了一个缓存的问题,没有更新的实体,当他们被加载一次。我们的实体使用应用程序时已经过时。

We are currently having a problem of architecture on a WPF application. It concerns EntityFramework context management, it’s instantiated once and used during the entire life of the application. So we end up with a cache issue, entities are not updated when they were loaded once. Our entities are obsolete when using the application.


  • WPF项目

  • .Net框架4客户端配置文件

  • MEF(在Framework 4.0 System.ComponentModel.Composition包含)

  • 设计模式MVVM

  • 多用户应用程序

这是当前架构的架构。


  • 管理业务规则调用(业务层)

  • 保存(通过的UnitOfWork)上下文后的业务规则做了

  • 只能由一个ViewModel
  • 被称为

  • 定义业务规则

  • 只能通过服务层被称为


  • 执行哪些变化背景下DATAS方法(插入,更新,删除)

  • 继承ReadOnlyRepository

  • 只能由业务层被称为


  • 执行方法,该方法返回DATAS(选择)

  • 随处称为(视图模型,服务层,业务层)


  • 管理方面instanciation

  • 保存上下文

  • 上下文仅适用于仓库

[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;
   }
}

服务层

public class OrderManagementService : IOrderManagementService
{
   private readonly IUnitOfWork _unitOfWork;
   private readonly IOrderManagementBusiness _orderManagementBusiness;

   [ImportingConstructor]
   public OrderManagementService (IUnitOfWork unitOfWork, IOrderManagementBusiness orderManagementBusiness)
   {
      _unitOfWork= unitOfWork;
      _orderManagementBusiness = orderManagementBusiness;
   }
}

业务层

public class OrderManagementBusiness : IOrderManagementBusiness
{
   private readonly IOrderReadOnlyRepository _orderReadOnlyRepository;

   [ImportingConstructor]
   public OrderManagementBusiness (IOrderReadOnlyRepository orderReadOnlyRepository)
   {
      _orderReadOnlyRepository = orderReadOnlyRepository;
   }
}

ReadOnlyRepository层

public class OrderReadOnlyRepository : ReadOnlyRepositoryBase<DataModelContainer, Order>, IOrderReadOnlyRepository
{
   [ImportingConstructor]
   public OrderReadOnlyRepository (IUnitOfWork uow) : base(uow)
   {
   }
}

ReadOnlyRepositoryBase

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);
   }

我们可以看到,背景是考虑到在构造函数库。选择方法使用AsNoTracking()方法不缓存​​的实体。这是一个临时的解决方案,这显然在长期不可行的。

We can see that the context is given to the repository in the constructor. Select methods use the "AsNoTracking ()" method to not cache entities. It's a temporary solution which is obviously not viable in long term.

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();
   }
}   

在与MEF服务的第一组合物的UnitOfWork将与实例化背景下的默认构造函数实例。

During the first composition of a service with MEF, UnitOfWork will be instantiated with the default constructor which instantiate the context.

code的一些作品已经为可读性省略。

Some pieces of code have been omitted for readability.

上下文的寿命显然是一个问题。知道,同样的服务方法内的所有调用必须共享相同的背景。

The lifetime of the context is clearly an issue. Knowing that all calls within the same service method must share the same context.

我们怎样才能考虑修改架构,避免单一的环境中?

How can we consider modifying the architecture to avoid having a single context ?

随意问的问题!如果需要,我可以将它突出问题一个测试项目。

Feel free to ask questions ! If needed, I can attach a test project which highlight the issue.

推荐答案

在你的应用程序,只有单个的工作单位,但不是他一个单位的目的的工作。相反,你需要在每次你与数据库的工作创建工作的单位。在你的情况的UnitOfWork 不应该是MEF容器的一部分,但你可以创建一个 UnitOfWorkFactory ,并从它注入容器。然后,服务可以创建一个的UnitOfWork 每次都的工作也要做的数据库:

In your application there is only single unit of work but that is not he purpose of a unit a work. Instead, you need to create a unit of work each time "you work with the database". In your case the UnitOfWork should not be part of the MEF container but you can create a UnitOfWorkFactory and inject it from the container. Then the services can create a UnitOfWork each time "work has to be done" with the database:

using (var unitOfWork = unitOfWorkFactory.Create()) {
  // Do work ...

  unitOfWork.Save();
}

我已经修改的UnitOfWork 所以它实现的IDisposable 。这将允许你处置EF背景和也说不定回滚事务,如果保存不叫。如果你不需要额外的事务处理,你甚至可以摆脱的UnitOfWork 类,因为它仅包装EF背景,而是你可以使用EF上下文为单位工作直接。

I have modified UnitOfWork so it implements IDisposable. This will allow you to dispose the EF context and also perhaps rollback a transaction if Save was not called. If you have no need for the extra transaction handling you can even get rid of the UnitOfWork class because it simply wraps the EF context and instead you can used the EF context as a unit of work directly.

这变化将改变迫使你修改如何服务和存储库的结构,但你真的要因为你的问题是,你有一个单独的工作单位存在应用程序的整个过程。

This change will change force you to modify how the service and the repositories are structured but you really have to because your issue is that you have a single unit of work that exists for the entire duration of the application.

这篇关于WPF /的EntityFramework上下文生存的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆