2013-07-08 4 views
46

В Entity Framework - есть ли способ получить вновь созданный идентификатор (идентификатор) внутри транзакции перед вызовом «SaveChanges»?Entity Framework - получить идентификатор до «SaveChanges» внутри транзакции

мне нужен идентификатор для второй вставки, однако он всегда возвращается как 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

Ой, надеялся, что есть способ, но Спасибо. – user1948635

ответ

38

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

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

Второй способ - не использовать базу данных, встроенную в поля IDENTITY, а реализовать их самостоятельно. Это может быть очень полезно, когда у вас много операций с объемной вставкой, но она поставляется с ценой - ее нетривиально реализовать.

EDIT: SQL Server 2012 имеет встроенный тип SEQUENCE, который можно использовать вместо столбца IDENTITY, без необходимости его реализации.

+1

Если мне нужно было вызвать «SaveChanges» после первой вставки, то вторая вставка не удалась - будет ли транзакция по-прежнему откатывать 1-ю вставку? – user1948635

+6

, конечно, это сделка. каждая операция в транзакции будет отброшена на 'rollback'. посмотрите http://en.wikipedia.org/wiki/ACID – SeriousM

+0

В Entity нет функции отката. Это похоже на проблему с курицей и яйцом. Единственный способ - выполнить немного чистого SQL и спросить DB, что будет следующей Identity. Но это не гарантируется, поскольку кто-то другой может это принять. Другое дело - написать SQL и вставить и пустую строку, чтобы зарезервировать его, но вы можете приземлиться с выделенными пустыми зарезервированными строками. – ppumkin

7

@zmbq является правильным, вы можете получить идентификатор после вызова изменений.

Мое предложение состоит в том, что вы НЕ должны полагаться на сгенерированные идентификаторы базы данных. База данных должна быть только деталью вашего приложения, а не неотъемлемой и неизменной частью.

Если вы не можете обойти эту проблему, используйте идентификатор GUID в качестве идентификатора из-за его уникальности. MSSQL поддерживает GUID как родной тип столбца и быстро (хотя и не быстрее INT).

Приветствия

+0

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

+0

, но это столбец INT, правильно? возможно, вы можете вставить TICK или уникальный номер, который вы создаете самостоятельно. – SeriousM

+0

Это, но есть большое количество пакетов SSIS, которые работают с базой данных, ожидающей столбца идентификации ... – user1948635

3

Если tblTest объект соединен с другими объектами, которые вы хотите прикрепить к сообщению, вы не должны иметь Id создать отношение. Давайте скажем tblTest прикрепляется к объекту anotherTest, это так, что в объекте anotherTest у вас есть tblTest объект и tblTestId свойства, в этом случае вы можете иметь этот код:

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; 
      .... 
     } 
    } 

После отправки отношения будут созданы и вы дон Не нужно беспокоиться об идентификаторах и т. д.

Смежные вопросы