2013-07-08 6 views
46

In Entity Framework: esiste un modo per recuperare un ID (identità) appena creato all'interno di una transazione prima di chiamare "SaveChanges"?Entity Framework: recupera ID prima di "Salva modifiche" all'interno di una transazione

Ho bisogno l'ID per un secondo inserto, tuttavia è sempre restituito come 0 ...

 ObjectContext objectContext = ((IObjectContextAdapter)context).ObjectContext; 

     objectContext.Connection.Open(); 

     using (var transaction = objectContext.Connection.BeginTransaction()) 
     { 
      foreach (tblTest entity in saveItems) 
      { 
       this.context.Entry(entity).State = System.Data.EntityState.Added; 
       this.context.Set<tblTest>().Add(entity); 

       int testId = entity.TestID; 

       .... Add another item using testId 
      } 

      try 
      { 
       context.SaveChanges(); 
       transaction.Commit(); 
      } 
      catch (Exception ex) 
      { 
       transaction.Rollback(); 
       objectContext.Connection.Close(); 
       throw ex; 
      } 
     } 

     objectContext.Connection.Close(); 
+3

http://stackoverflow.com/questions/6029711/id-of-newly-added-entity-before-savechanges – Zaki

+0

Oh, speravo ci fosse un modo, ma grazie. – user1948635

risposta

38

L'ID viene generato dal database dopo la riga viene inserita nella tabella. Non puoi chiedere al database quale sarà quel valore prima che la riga venga inserita.

Ci sono due modi per aggirare questo: il più semplice sarebbe chiamare SaveChanges. Dato che ci si trova all'interno di una transazione, è possibile eseguire il rollback in caso di problemi dopo aver ottenuto l'ID.

Il secondo modo sarebbe non utilizzare i campi del database integrati in IDENTITY, ma piuttosto implementarli da soli. Questo può essere molto utile quando si hanno molte operazioni di inserimento di massa, ma viene fornito con un prezzo - non è banale da implementare.

MODIFICA: SQL Server 2012 ha un tipo SEQUENCE incorporato che può essere utilizzato al posto di una colonna IDENTITY, non è necessario implementarlo manualmente.

+1

Se dovessi chiamare "SaveChanges" dopo il primo inserimento, quindi il secondo inserto non funziona, la transazione potrebbe comunque riportare indietro il primo inserto? – user1948635

+6

ovviamente, ecco di cosa tratta una transazione. ogni operazione in una transazione verrà ripristinata su 'rollback'. dare un'occhiata a http://en.wikipedia.org/wiki/ACID – SeriousM

+0

Non esiste alcuna funzionalità di rollback in Entity. È come il problema dell'uovo e della gallina. L'unico modo è di eseguire un po 'di puro SQL e chiedere al DB quale sarà la prossima identità. Ma questo non è garantito dal momento che qualcun altro può prenderlo. L'altra cosa è scrivere SQL e inserire e svuotare la riga per riservarla, ma si potrebbe finire con l'assegnazione di righe riservate vuote. – ppumkin

7

@zmbq ha ragione, è possibile ottenere l'ID dopo aver chiamato le modifiche di salvataggio.

Il mio suggerimento è che NON si deve fare affidamento sull'ID generato del database. Il database dovrebbe solo un dettaglio della vostra applicazione, non una parte integrante e non modificabile.

Se non è possibile aggirare il problema, utilizzare un GUID come identificatore a causa della sua unicità. MSSQL supporta GUID come tipo di colonna nativa ed è veloce (anche se non più veloce di INT.).

Acclamazioni

+0

Purtroppo cambiare i campi ID ora causerebbe problemi con altri aspetti dell'applicazione, significherebbe un grande cambiamento che sto cercando di evitare. – user1948635

+0

ma è una colonna INT, giusto? forse puoi inserire un TICK o un numero univoco da te creato. – SeriousM

+0

Lo è, ma c'è un gran numero di pacchetti SSIS che girano contro il database che si aspetta una colonna di identità ... – user1948635

3

Se il soggetto tblTest è collegato ad altre entità che si desidera allegare, non è necessario avere la Id per creare la relazione. Diciamo tblTest è collegato a oggetto anotherTest, è il modo in cui in oggetto anotherTest avete tblTest proprietà degli oggetti e tblTestId, in questo caso si può avere questo codice:

using (var transaction = objectContext.Connection.BeginTransaction()) 
    { 
     foreach (tblTest entity in saveItems) 
     { 
      this.context.Entry(entity).State = System.Data.EntityState.Added; 
      this.context.Set<tblTest>().Add(entity); 

      anotherTest.tblTest = entity; 
      .... 
     } 
    } 

Dopo la presentazione della relazione sarebbe stato creato e si don Non c'è bisogno di preoccuparsi di Id ed ecc.

Problemi correlati