Entity Framework: атомарная транзакция (контекст базы данных)

#c# #sql #.net

#c# #sql #.net

Вопрос:

я имею дело с Entity framework 4, поскольку приложение уже создано, и мне нужно внести в него некоторые изменения.

Сценарий: реализовал DbTransaction (вставляет данные в базу данных) в моем коде, и как только транзакция прерывается на полпути и выполняется откат, то в следующий раз, когда та же транзакция выполняется с правильными / проверенными данными, транзакция все равно прерывается, предоставляя предыдущее исключение. Это довольно сложно понять, поскольку я предполагаю, что откат должен удалить сообщения проверки и данные из контекста базы данных, поскольку это 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.

Поскольку у меня возникают проблемы со сложностью при повторном создании контекста, поэтому я ищу более подходящее решение. Заранее спасибо.

Комментарии:

1. Не используйте статический DatabaseContext. Создайте ее по мере необходимости. Также ваша ручная обработка транзакции SQL не требуется.

2. Каковы «проблемы сложности при повторном создании контекста»?

3. Не используйте статический DbContext, поскольку он не предназначен для потокобезопасности. Также всегда используйте using оператор, чтобы, если что-то пойдет не так, контекст откатывал любые изменения.

4. Создайте контекст как можно позже и утилизируйте его как можно скорее (используйте using!). Конечно, не статический. Если у вас есть «проблемы со сложностью», сначала устраните их; затем используйте контекст правильно, как упоминалось ранее другими.

5. На самом деле в приложении контекст создается в конструкторе и используется во всем приложении. Правильно ли это использовать объекты контекста?

Ответ №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 для каждой транзакции. поэтому всегда пытайтесь создать новый DataContext и уничтожить его, как только ваша транзакция завершится. Надеюсь, это сработает!

Комментарии:

1. да! Я понял вашу точку зрения не создавать статический объект контекста. В любом случае проблема заключается в том, что объекты контекста инициализируются в конструкторе и используются во всем приложении. В сценарии атомной транзакции, когда транзакция прерывается на полпути, объекты контекста сохраняют исключение. В следующий раз, когда я попытаюсь использовать этот контекст, он покажет мне предыдущее исключение. Почему это так?

2. это связано с тем, что вы снова используете «неисправный» DataContext.

3. Если вам нужен один и тот же объект в одном классе, то зачем вам нужно делать его статичным? Это вызовет проблему, потому что, если вы создали несколько объектов TestClass, будет использоваться один и тот же грязный DataContext. Поскольку DataContext должен иметь минимальное время жизни.

4. вы также можете создать экземпляр нестатического DataContext в классе, который можно использовать повсюду с одним и тем же объектом.

5. Я понимаю цель и преимущество повторного создания DataContext. Если я не могу повторно создать экземпляр, есть ли какие-либо обходные пути для обновления или очистки DbContext?