如何推迟在webform的不同方法中运行的多个上下文的context.savechanges?

时间:2017-03-30 13:21:02

标签: c# asp.net entity-framework webforms dbcontext

我想做的是处理不同的上下文(在单独的方法中声明)并以专用方法推迟每个上下文SaveChanges(),因为相互影响的相互作用DB

这里的问题是我正在开发一个webform:这是POSTBACK的土地。因此,为页面声明单个上下文将触发多个上下文错误,因为在每次回发之后将创建新的上下文。如果我dispose上下文以避免回发问题,我会丢失当前事务中的所有数据(不是我想要的)

如果我使用utilities课怎么办?这可以允许创建静态上下文。我被告知这不是一个好主意。

我尝试过序列化。我的xmlserializer并不想序列化我的DbSet对象和我的实体类类型。我不想将数据保存在列表中以避免内存问题,因为正在处理大量数据。

在我的webform的代码behing结构下面

如何

protected void MyMethod1()
{
    using(var = context1 = new MyDbContext())
    {// Do some work BUT no context1.SaveChanges()}
}

protected void MyMethod2()
{
    MyMethod1();
    using(var = context2 = new MyDbContext())
    {// Do some work BUT no context2.SaveChanges()}
}

protected class MeMethod3()
{
     context1.SaveChanges();
     context2.SaveChanges();
}

1 个答案:

答案 0 :(得分:1)

您正在寻找的解决方案涉及2项变更:

  1. 为Context Manger声明一个独立的类。

    public class DbContextManager<C> : IDisposable where C : DbContext
    
  2. 在此类中,声明一个返回打开的Context的公共静态方法:

        public static DbContextManager<C> GetManager()
    

    每次需要打开上下文连接时,只需将其称为:

        using (var ctx = ContextManager<YourContext>.GetManager())
    

    您应将[YourContext]定义为:

        public partial class YourContext : DbContext
    

    每次调用ContextManager.GetManager()时,都应该检查内部关联的上下文(类型C的私有属性:private C _context;)是否打开。如果没有,它只是创建一个新的上下文并在内部保存它的引用(到C类型的私有静态属性)。或者,您也可以将其保存为系统用于存储广泛系统变量的某些全局属性上下文中的参考。

    它还向内部整数计数器添加1,表示此ContextManager处理的引用数量。

    所有CRUD操作都应在声明的using (var ctx = ContextManager<YourContext>.GetManager())

    内执行

    当您的代码退出using块时,ContextManager会执行它的Dispose()方法(因为该类应该实现IDisposable)。在\ Dispose()方法中,您应该DeRef您的内部整数计数器。当你的内部计数器达到0时,你应该释放你打开的DbContext,因为不需要额外的上下文操作。

    对于使用您系统的每个会话,这将为您提供共享/保持与数据库的1个开放连接的好处。

    在更新多线程环境中的静态属性/字段之前,请记住使用lock (_lock)(object _lock)。

    1. 使用Native .Net Transactions:为了推迟实际的SaveChanges()执行,在打开上下文之前,请使用TransactionScope(..)块:

      using (TransactionScope tr = new TransactionScope())
      
    2. 退出using(TransactionScope...)后,所有SaveChanges()实际上都会持久保存到数据库中。如果在执行CRUD操作时出现问题,TransactionScope将负责为您回滚所有内容。

      如果您嵌套using (TransactionScope tr = new TransactionScope()),或者您打开了多个DbContext连接,.Net事务管理器将自动升级到Enterprise Services,并将自动在所有指定的Windows服务器上使用Windows Distributed Transaction Coordinator Service你打开的DbContext连接。在这种情况下,您还应该在所有参与的Sql服务器上配置所有DTC,以便能够[看到并相互交谈]以完成此复杂方案。

      如果你需要一个有效的DbContextManager课程,请告诉我,我会附上一个作为例子。