Entity framework 6.0: как я могу обеспечить целостность транзакций между двумя объектами, где одному требуется присвоенный идентификатор другого объекта?

Я видел множество вопросов и советов по многократному вызову dbContext.SaveChanges в транзакции. Некоторые говорят, что этого следует избегать. Этот подробный пост действительно стоит прочитать http://mehdi.me/ambient-dbcontext-in-ef6/

В моем конкретном сценарии объект B имеет ссылку Id на объект A.

Во время сценария создания я создаю A и вызываю savechanges, чтобы получить A.Id, назначенный базой данных. Затем я создаю Entity B как новый B(A.Id,....) и снова вызываю savechanges. Это могло бы выглядеть так в псевдокоде

using(var tx =  dbContext.BeginTransaction())
{
    var a = new A();
    dbContext.Add(a);  //a.Id is null
    dbContext.saveChanges(); // a.Id has now been initialized

    var b = new B(a.Id); //I want to create b in a valid state so a.Id  cannot be null
    dbContext.SaveChanges();
    tx.Commit();
}

(Я знаю, что в псевдокоде отсутствует логика обработки исключений...)

Почему это проблема ? Это из-за того, что сохранения нельзя откатить?

Я знаю, что мог бы переделать, но это невозможно, потому что мы делим базу данных с некоторыми устаревшими системами, поэтому базу данных нельзя легко изменить, если это вообще возможно!

Что такое альтернативное решение?


person Christian Johansen    schedule 08.03.2016    source источник
comment
В чем вопрос, учитывая, что Entity Framework поддерживает явные транзакции? Вы, кажется, пишете псевдокод для функции, которую вы, кажется, упускаете, в то время как ваш псевдокод на самом деле вызывает метод, который существует. Вы не заморачивались с документацией? msdn.microsoft.com/en-us/data/dn456843.aspx Работа с транзакциями (начиная с EF6).   -  person TomTom    schedule 08.03.2016
comment
SaveChanges использует внутреннюю транзакцию. Изменение назначений уже атомарно. В чем собственно вопрос? То, что кто-то где-то написал, что вы должны вызывать SaveChanges несколько раз, не означает, что это правильно. На самом деле, почему ваш код вызывает его дважды??.   -  person Panagiotis Kanavos    schedule 08.03.2016
comment
Нет причин назначать идентификаторы, если вы используете правильные отношения. EF распознает новые/измененные классы и сгенерирует операторы SQL, которые будут вставлять новые объекты в правильном порядке.   -  person Panagiotis Kanavos    schedule 08.03.2016
comment
Спасибо за комментарии. Да, я прочитал статью о работе с транзакциями. В некоторых случаях я мог бы предпочесть только ссылку по идентификатору и не иметь объектного отношения. Мой код вызывает SaveChanges в первый раз, чтобы получить идентификатор A, чтобы я мог инициализировать B. У меня есть два вопроса: 1) Мне не ясно, почему дважды вызывать savechages плохо. 2) Альтернативные пути решения проблемы. Я ценю предложения, которые вы дали ..   -  person Christian Johansen    schedule 10.03.2016


Ответы (1)


Используйте свойство навигации следующим образом:

public class A
{
    [Key]
    public int Id { get; set; }

    public int BId { get; set; }

    [ForeignKey("BId")]
    public B B { get; set; }
}

public class B
{
    [Key]
    public int Id { get; set; }
}

затем просто назначьте вновь созданный B свойству навигации A:

using (var transaction = dbContext.BeginTransaction())
{
    var a = new A();
    a.B = new B();
    dbContext.Add(a);
    dbContext.saveChanges();
    transaction.Commit();
}
person user1859022    schedule 08.03.2016
comment
SaveChanges уже использует транзакцию. Помимо этого, использование свойства навигации является правильным способом обработки отношений. - person Panagiotis Kanavos; 08.03.2016
comment
@PanagiotisKanavos: правильно - просто хотел, чтобы код был похож на псевдокод OP :) - person user1859022; 08.03.2016