Требовать идентификатор от SaveChanges при сохранении? Структура сущности

Я вставляю запись в базу данных, которая выглядит так:

class Transaction
{
   int Id;
}

Что я хочу, так это то, что когда я вставляю этот объект, я хочу создать еще одну запись, например:

class TransactionUpdate
{
   int StartingTransactionId;
   int EndingTransactionId;
}

Что у меня есть до сих пор, так это цикл в моем SaveChanges в DbContext, который берет новые объекты Transaction, которые будут созданы, создает объекты TransationUpdate и прикрепляет их к DbContext.

public override int SaveChanges()
 {
   foreach(var entry in this.ChangeTracker.Entries())
   {
     if(entry.Entity is Transaction)
     {
       var update = new TransactionUpdate();
       update.StartingTransactionId = ((Transaction)entry.Entity).PreviousTransactionId;
       update.EndingTransactionId = ((Transaction)entry.Entity).Id; // This is zero because the entity has not been inserted.
       this.TransactionUpdates.Add(update);
     }
   }
 }

Проблема в том, что я не могу правильно создать TransactionUpdate, потому что у меня нет «EndingTransactionId» или идентификатора транзакции, которую я вставляю в данный момент.

Как я могу решить эту проблему?

Огромное спасибо.

РЕШЕНО

Я сделал то, что предложил Ладислав, и теперь создаю список элементов для добавления вместе со ссылками на объекты, необходимые для их вставки. Таким образом:

    public override int SaveChanges()
    {
        var transactionUpdatesToAdd = new List<Tuple<TransactionUpdate, Transaction>>();

        foreach (var entry in this.ChangeTracker.Entries<Transaction>())
        {
            if (entry.State == EntityState.Added)
            {
                var update = new TransactionUpdate();
                update.StartingTransactionId = ((Transaction)entry.Entity).PreviousTransactionId;
                transactionUpdatesToAdd.Add(new Tuple<TransactionUpdate, Transaction>(update, entry.Entity));
            }
        }

        using(var scope = new TransactionScope())
        {
         // Save new Transactions
         base.SaveChanges();

         // Update TransactionUpdates with new IDs
         foreach (var updateData in transactionUpdatesToAdd)
         {
             updateData.Item1.EndingTransactionId = updateData.Item2.Id;
             this.TransactionUpdates.Add(updateData.Item1);
         }

         // Insert the new TransactionUpdate entities.
         return base.SaveChanges();
        }

person James    schedule 01.02.2011    source источник


Ответы (2)


Основываясь на вашем описании, я предполагаю, что вы используете автоматически сгенерированный идентификатор в базе данных. Вы не получите этот идентификатор перед выполнением SaveChanges в контексте. Вы должны разделить операцию на две отдельные модификации:

public override int SaveChanges()  
{  
   // call base context saving operation to insert all Transactions
   base.SaveChanges();

   foreach(var entry in this.ChangeTracker.Entries())    
   {      
      if(entry.Entity is Transaction)      
      {        
         var update = new TransactionUpdate();        
         update.StartingTransactionId = ((Transaction)entry.Entity).PreviousTransactionId;        
         update.EndingTransactionId = ((Transaction)entry.Entity).Id;      
         this.TransactionUpdates.Add(update);      
      }    
   }

   // save changes again to insert all TransactionUpdates
   base.SaveChanges();  
} 

Вы должны обернуть его в TransactionScope, чтобы выполнить полное сохранение как атомарную операцию.

person Ladislav Mrnka    schedule 01.02.2011
comment
Я хотел избежать этого, мне было интересно, есть ли какие-либо события, к которым я мог бы подключиться внутри EF? - person James; 01.02.2011
comment
@James: Нет, после сохранения не происходит никаких событий. Вы можете запускать пользовательское событие в своей реализации SaveChanges, но в итоге вы получите тот же код. IMO, нет способа сделать это без двойного вызова SaveChanges или создания идентификаторов в вашем приложении. Нет причин избегать двойного вызова SaveChanges, поскольку EF не поддерживает пакетную обработку команд. - person Ladislav Mrnka; 01.02.2011

Если вы не вставили TransactionId, он все равно есть в вашем объекте. Передайте свой объект в качестве параметра перегруженному методу SaveChanges и используйте его для передачи идентификатора

person CynicalSection    schedule 01.02.2011