Search code examples
entity-frameworkentity-framework-4entity-framework-ctp5

Requiring an Id from SaveChanges, whilst saving? Entity Framework


I am inserting a record into the database, which looks like this:

class Transaction
{
   int Id;
}

What I want, is when I insert this object, I want to create another record, like this:

class TransactionUpdate
{
   int StartingTransactionId;
   int EndingTransactionId;
}

What I have so far, is a loop in my SaveChanges on the DbContext, which takes new Transaction objects that will be created and creates TransationUpdate objects and attaches these to the 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);
     }
   }
 }

The problem is, I cannot properly create a TransactionUpdate because I do not have 'EndingTransactionId', or, the Id of the Transaction I am currently inserting.

How can I solve this problem?

Many Thanks.

SOLVED

I have done what Ladislav suggested and am now creating a list of items to add, along with references to the objects that are required to insert them. Thus:

    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();
        }

Solution

  • Based on your description I guess you are using autogenerated Id in database. You will not receive this Id befere executing SaveChanges on the context. You have to divide operation into two separate modifications:

    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();  
    } 
    

    You should wrap it into TransactionScope to perform whole saving as atomic operation.