【问题标题】:Entity Framework: Atomic Transaction (Database context)实体框架:原子事务(数据库上下文)
【发布时间】:2016-10-13 18:39:56
【问题描述】:

我正在处理实体框架 4,因为应用程序已经构建,我必须在其中进行一些渐变。

场景: 在我的代码中实现了一个 DBTransaction(在数据库中插入数据),一旦一个事务在中途中止并回滚执行,那么下次当相同的事务使用正确/验证的数据执行时,事务仍然通过给出先前的异常中止。很难理解,因为我认为 RollBack 应该从数据库上下文中删除验证消息和数据,因为它是 SQL。 注意:我一直在使用静态 DatabaseContext。

public class TestClass
{
    static SampleDataBaseEntities ctx = new SampleDataBaseEntities();

    public void SqlTransaction()
    {
        ctx.Connection.Open();
        using (DbTransaction transaction = ctx.Connection.BeginTransaction())
        {
            try
            {
                Student std = new Student();
                std.first_name = "first";
                //std.last_name = "last"; (This is responsible for generating the exception)
                AddTeacher();
                ctx.AcceptAllChanges();
                transaction.Commit();
            }
            catch (Exception e)
            {
                transaction.Rollback();
            }
            finally
            {
                ctx.Connection.Close();
            }
        }
    }

    public void SqlTransaction2()
    {
        ctx.Connection.Open();
        using (DbTransaction transaction = ctx.Connection.BeginTransaction())
        {
            try
            {
                Student std = new Student();
                std.first_name = "first";
                std.last_name = "last";
                AddTeacher();
                ctx.Students.AddObject(std);
                ctx.SaveChanges(false);
                transaction.Commit();
                ctx.AcceptAllChanges();
            }
            catch (Exception e)
            {
                transaction.Rollback();
                transaction.Dispose();
                ctx.Connection.Close();
            }
        }
    }

    public void AddTeacher()
    {
        Teacher t = new Teacher();
        t.first_name = "teacher_first";
        t.last_name = "teacher_last";
        t.school_name = "PUCIT";
        ctx.Teachers.AddObject(t);
        ctx.SaveChanges(false);
    }
}

class Program
{
    static void Main(string[] args)
    {
        TestClass test = new TestClass();
        test.SqlTransaction();
        test.SqlTransaction2();
    }
}

解决方案(我已经尝试过): 使用 SaveChanges(false)。 使用 SaveChanges(false) 和 ctx.AcceptAllChanges()。

解决方法: 我得到的解决方法是重新实例化 DatabaseContext 对象。

由于我在重新实例化上下文时遇到了复杂性问题,这就是为什么要寻找更合适的解决方案。 提前致谢。

【问题讨论】:

  • 不要使用静态 DatabaseContext。根据需要创建一个。此外,您不需要手动处理 SQL 事务。
  • 什么是“重新实例化上下文的复杂性问题”?
  • 不要使用静态 DbContext,因为它不是线程安全的。还要始终使用using 语句,这样如果出现任何问题,上下文将回滚任何更改。
  • 尽可能晚地创建上下文并尽快处理它(使用 using!)。当然不是静态的。如果您有“复杂性问题”,请首先解决这些问题;然后以正确的方式使用上下文,正如其他人之前提到的那样。
  • 实际上在应用程序中,上下文是在构造函数中创建的,并在整个应用程序中使用。这是使用上下文对象的正确方法吗?

标签: c# sql .net


【解决方案1】:

所有问题都来自于没有创建上下文的新实例。将您的代码简化为此,它应该可以工作。

using (var ctx = new SampleDataBaseEntities()) {
    Student std = new Student();
    std.first_name = "first";
    std.last_name = "last";
    ctx.Student.Add(std);
    ctx.SaveChanges();
}

【讨论】:

    【解决方案2】:

    “我得到的解决方法是重新实例化 DatabaseContext 对象。”

    是的,这对于再次进行交易是正确的。 由于您使用的是静态数据上下文,因此下次您进行事务时使用相同的数据上下文,这会导致您重新输入数据和验证错误时出现问题。

    解决方案:尽量不要使用静态数据上下文,因为您很快就会进行交易。因此,您需要为每个事务更新数据上下文。所以总是尝试实例化一个新的 dataContext 并在事务完成后立即销毁它。 希望它会工作!

    【讨论】:

    • 是的!我明白你的意思是不要创建一个静态的上下文对象。任何问题是如何在构造函数中初始化上下文对象并在整个应用程序中使用。在原子事务场景中,当事务中途终止时,上下文对象保持异常。下次当我尝试使用该上下文时,它会向我显示上一个异常。为什么会这样?
    • 这是因为您再次使用“错误”的 dataContext。
    • 如果你需要同一个类中的同一个对象,那你为什么要把它变成静态的呢?这将导致问题,因为如果您创建了多个 TestClass 对象,将使用相同的脏数据上下文。因为 DataContext 应该有最短的生命周期。
    • 您还可以在类中实例化非静态 DataContext,该类可用于同一个对象。
    • 我了解 DataContext 重新实例化的目的和优势。如果我无法重新实例化,是否有任何解决方法可以刷新或清理 DbContext?
    猜你喜欢
    • 1970-01-01
    • 2023-04-05
    • 1970-01-01
    • 2021-05-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多