Як я можу отримати Id вставленої сутності в рамках Entity? [зачинено]


611

У мене проблема з Entity Framework в Asp.net. Я хочу отримати значення Id щоразу, коли я додаю об'єкт у базу даних. Як я можу це зробити?


16
Відповідь Ладіслава Мрнка нижче - правильна відповідь, і її слід прийняти як таку.
CShark

3
ОП опублікував лише один раз зі своїм обліковим записом, це питання буде більш конкретним. Це дало йому / їй майже 2 тис. Репутації (!), Відповідь не позначена як прийнята, оскільки рахунок з цього дня припинено.
MurariAlex

1
Якщо вам просто потрібен Id для того, щоб використовувати його у відносинах із зовнішнім ключем, ви можете замість цього просто встановити навігаційну властивість вашого залежного об'єкта до раніше доданої сутності. Таким чином, вам не потрібно займатись дзвінками SaveChangesвідразу, щоб отримати ідентифікатор. Подальше читання тут .
B12Toaster

Для Entity Framework Core 3.0 додайте параметр acceptAllChangesOnSuccess як істинний: wait _context.SaveChangesAsync (true);
Майк

Відповіді:


1005

Це досить просто. Якщо ви використовуєте генеровані БД ідентифікатори (наприклад, IDENTITYу MS SQL), вам просто потрібно додати сутність до пов’язаних ObjectSetта SaveChangesінших ObjectContext. Idбуде автоматично заповнено для вас:

using (var context = new MyContext())
{
  context.MyEntities.Add(myNewObject);
  context.SaveChanges();

  int id = myNewObject.Id; // Yes it's here
}

Кожна структура за замовчуванням слідує за кожним INSERT з , SELECT SCOPE_IDENTITY()коли автоматично генеруються Idвикористовуються s.


34
Отже, ви ставите неправильне запитання. Якщо у вас є проблема з виключенням, вам слід задати питання, де відображаються винятки (і внутрішній виняток) та фрагмент коду, що викликає цю помилку.
Ladislav Mrnka

3
Переконайтесь, що додана вами особа є дійсною суттю, наприклад, все, що має обмеження в базі даних "ненулеве", повинно бути заповнене тощо.
Франц

4
@LadislavMrnka: А як щодо навігаційних властивостей новоствореного об’єкта? Схоже, вони автоматично не заповнюються після збереження змін.
Ісаак Кляйнман

4
Розглянемо наступний сценарій: table1 повинен генерувати ідентичність @@, щоб використовувати його в table2. Як таблиця1, так і таблиця2 мають бути в одній транзакції, наприклад, одна операція SaveChange повинна зберігати дані обох таблиць. Ідентифікатор @@ не буде генеровано, якщо не буде викликано "SaveChanges". як ми можемо вирішити цю ситуацію?
Араш

7
@Djeroen: Якщо ви використовуєте ідентифікований базу даних, вам потрібно спочатку вставити ці об'єкти в базу даних. Якщо вам потрібно мати ідентифікатори перед вставкою, ви повинні створити власну логіку, щоб отримати унікальні ідентифікатори перед тим, як вставляти дані, і не використовувати стовпчик ідентичності в базі даних.
Ладислав Мрнка

124

Я використовував відповідь Ладіслава Мрнка для успішного отримання ідентифікаційних файлів під час використання Entity Framework, однак я публікую тут повідомлення, тому що я його пропустив (тобто використовував його там, де цього не потрібно) і думав, що опублікую свої висновки тут - У випадку, коли люди прагнуть «вирішити» проблему, яку я мав.

Розглянемо об'єкт Замовлення, який має зовнішній ключ із Замовником. Коли я додав нового клієнта і нове замовлення одночасно, я робив щось подібне;

var customer = new Customer(); //no Id yet;
var order = new Order(); //requires Customer.Id to link it to customer;
context.Customers.Add(customer);
context.SaveChanges();//this generates the Id for customer
order.CustomerId = customer.Id;//finally I can set the Id

Однак у моєму випадку цього не потрібно, оскільки у мене виникли зовнішні ключові відносини між замовником.Ід та замовленням. Замовник

Все, що я мав зробити, це було;

var customer = new Customer(); //no Id yet;
var order = new Order{Customer = customer}; 
context.SaveChanges();//adds customer.Id to customer and the correct CustomerId to order

Тепер, коли я зберігаю зміни, ідентифікатор, який генерується для клієнта, також додається до замовлення. Я не потребую додаткових кроків

Я усвідомлюю, що це не дає відповіді на початкове запитання, але я вважаю, що це може допомогти розробникам, які не знайомі з EF, від надмірного використання голосового відповіді на щось, що може не потрібно.

Це також означає, що оновлення завершуються однією транзакцією, потенційно уникаючи даних про орфін (або всі оновлення завершені, або жодні).


8
Дякую ! ВАЖЛИВО Порада з найкращих практик: замовлення вар = нове замовлення {клієнт = замовник}; Це показує силу Entity Framework призначати пов'язаний об'єкт, і Id автоматично оновлюється.
LA Guy 88

Дякуємо за цю додаткову інформацію до відповіді. Був дуже корисним для збереження прямолінійної бази даних при використанні EF.
Прасад Корхале

Дуже дякую за це. Це саме те, що я шукав. Я просто вірив, що може бути спосіб кращий, ніж два рази викликати "SaveChanges"
Josh

1
Будь ласка, зазначте у своїй відповіді (бажано, жирними літерами), що це вирішує поведінку угоди. Якщо один із об’єктів не вдалося додати, частина транзакції не буде успішною. Наприклад, додавання людини та учня. Людина досягає успіху, а студент зазнає невдачі. Зараз людина надмірна. Дякую за це чудове рішення, хоча!
Імран Фарукі

32

Вам потрібно перезавантажити об'єкт після збереження змін. Тому що це було змінено тригером бази даних, який неможливо відстежити EF. Отже, нам потрібно перезавантажити об'єкт знову з БД,

db.Entry(MyNewObject).GetDatabaseValues();

Тоді

int id = myNewObject.Id;

Подивіться на відповідь @jayantha у нижченаведеному питанні:

Як я можу отримати Id вставленої сутності в рамках Entity при використанні defaultValue?

Подивіться на відповідь @hristian у нижченаведеному питанні:

Контекст оновлення Entity Framework?


2
Привіт, коли мені це подобається, я отримую помилку компіляції, яка говорить: не можна вирішити властивості, наприклад, Id чи Name, чи можете ви мені допомогти?
Morteza Azizi

1
@MortezaAzizi Здається, це помилка не вирішеної проблеми або проблема з недійсною властивістю, але ви можете, будь ласка, пояснити або написати якийсь фрагмент коду?
QMaster

3
Не слід цього робити, .GetDatabaseValues();якщо ви просто зберегли свою модель в БД. Ідентифікатор повинен автоматично переселятися в модель.
vapcguy

3
@QMaster За винятком того, що EF також може (і робить) виконувати той самий оператор SQL і заповнює ідентифікатор вашого об'єкта. В іншому випадку, як це можливо зберегти кілька залежних об'єктів одночасно? Як це можна було б зробити, GetDatabaseValues()якщо він не знає ідентифікатор об'єкта, який потрібно шукати в базі даних?
крильгар

2
@vapcguy Я бачу. Дякую за увагу Я перевірю, що в обох версіях EF ASAP.
QMaster

16

Перейдіть за цим посиланням.

http://www.ladislavmrnka.com/2011/03/the-bug-in-storegeneratedpattern-fixed-in-vs-2010-sp1/

Ви повинні встановити властивість StoreGeneratedPattern на ідентичність та спробувати власний код.

Або ви також можете використовувати це.

using (var context = new MyContext())
{
  context.MyEntities.AddObject(myNewObject);
  context.SaveChanges();

  int id = myNewObject.Id; // Your Identity column ID
}

7
Те саме, що відповідь зверху проголосував.
Lewis86

2
StoreGeneratedPatternбула для мене відсутнім твором.
БернсБА

1
Це шлях до роботи з ORACLE та ON-Insert Trigger,
Карл

посилання порушено - припаркований домен
t.durden

Привіт з Oracle. Мені довелося встановити StoreGeneratedPattern в Entity - перейдіть до програми перегляду моделей, знайдіть таблицю та ПК, виберіть властивість StoreGeneratedPattern та встановіть Identity. Він працює, як зазначено вище у відповіді. Це стосується випадку, коли у вас є тригер, який заповнює ваш ПК із послідовності на вставці.
Роб

15

Об'єкт, який ви зберігаєте, повинен мати правильний результат Idпісля розповсюдження змін у базі даних.


27
ви бачили внутрішній виняток? ;-)
Snowbear

6

Ідентифікатор можна отримати лише після збереження, натомість ви можете створити новий Посібник та призначити його перед збереженням.


4

Мені трапляється ситуація, коли мені потрібно вставити дані в базу даних і одночасно вимагати основний ідентифікатор, використовуючи структуру сутності. Рішення:

long id;
IGenericQueryRepository<myentityclass, Entityname> InfoBase = null;
try
 {
    InfoBase = new GenericQueryRepository<myentityclass, Entityname>();
    InfoBase.Add(generalinfo);
    InfoBase.Context.SaveChanges();
    id = entityclassobj.ID;
    return id;
 }

4

Всі відповіді дуже добре підходять для їх власних сценаріїв. Що я зробив по-різному, це те, що я призначив int PK безпосередньо з об'єкта (TEntity), який Add () повернувся до змінної int, як це;

using (Entities entities = new Entities())
{
      int employeeId = entities.Employee.Add(new Employee
                        {
                            EmployeeName = employeeComplexModel.EmployeeName,
                            EmployeeCreatedDate = DateTime.Now,
                            EmployeeUpdatedDate = DateTime.Now,
                            EmployeeStatus = true
                        }).EmployeeId;

      //...use id for other work
}

тому замість створення цілого нового об’єкта ви просто берете те, що хочете :)

РЕДАКЦІЯ Для пана @GertArnold:

введіть тут опис зображення


3
Не дуже корисно додавати не розкритий метод для призначення ідентифікатора. Це навіть не пов’язано з Entity Framework.
Герт Арнольд

1
@GertArnold .. У мене було те саме питання, що і в ОП, я знайшов відповіді і вніс це в одне рядкове твердження, і я ніколи не чув про те, щоб термін нерозкритий метод піклувався пояснити?
IteratioN7T

3
Це просто означає, що ви не показуєте (не розкриєте) все, що робите. Можливо, це просто не чітко описано, я не знаю. Що я знаю, це те, що Add(якщо це так DbSet.Add) не магічно присвоює значення EmployeeId.
Герт Арнольд

3
Не без цього SaveChanges. Неможливо. Якщо у вас є якийсь інший процес, який призначається EmployeeId, наприклад, у Employeeконструкторі s. АБО ви використовуєте ядро ​​EF ForSqlServerUseSequenceHiLo. У всякому разі, ви не даєте всієї картини.
Герт Арнольд

3
Моє останнє зауваження буде: це не стандартна поведінка EF. Ви повинні детальніше розповісти про своє оточення. Версія EF, марка та версія бази даних, клас працівника, його деталізація.
Герт Арнольд

3
Repository.addorupdate(entity, entity.id);
Repository.savechanges();
Var id = entity.id;

Це спрацює.


4
Репозиторій не несе відповідальності за збереження змін у базі даних. Це робота UnitOfWork.
tchelidze

5
Більше того, абсолютно незрозуміло, що Repositoryтаке. І "це спрацює" - це якесь пояснення !.
Герт Арнольд

2

Є дві стратегії:

  1. Використовувати ID( intабо GUID) генерувати Базу даних

    Мінуси:

    Ви повинні виконати SaveChanges()для отримання IDщойно збережених об'єктів.

    Плюси:

    Може використовувати intідентичність.

  2. Використовуйте створений клієнтом ID- лише GUID.

    Плюси: мінімізація SaveChangesоперацій. Здатний вставляти великий графік нових об'єктів за одну операцію.

    Мінуси:

    Дозволено лише для GUID


1

При першому використанні коду EF 6.x

    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public Guid Id { get; set; }

і ініціалізувати таблицю бази даних, вона поставить a

(newsequentialid())

всередині властивостей таблиці під заголовком Значення за замовчуванням або Прив'язка, що дозволяє заповнювати ідентифікатор під час його вставки.

Проблема полягає в тому, якщо ви створите таблицю і додасте

[DatabaseGenerated(DatabaseGeneratedOption.Identity)]

частина пізніше майбутні бази оновлень не додадуть назад (newsequentialid ())

Виправити правильний спосіб - це стерти міграцію, видалити базу даних та повторно перемістити ... або просто додати (newsequentialid ()) у дизайнер таблиці.


Чи можете ви детальніше розповісти про те, куди йде новий followentialid ()? У мене вже є моделі баз даних, створені вручну, спочатку не використовують код EF, і він не заповнює ідентифікатор, оскільки це не мій основний ключ. Я б хотів знайти рішення для цього.
Джош

1
@josh Припустимо, що кодом спочатку є тип Guid, клацніть правою кнопкою миші вашу таблицю в Sql Server Management Studio, клацніть стовпчик Id, і на вкладці Властивості стовпців всередині (Загальне) ви побачите значення за замовчуванням або прив’язка. Якщо ви створюєте таблиці БД вручну, зверніться до NewSequencesId або NewId . Загальний випадок використання чимось схожийwhen -column- is NULL, then NEWID()
Джефф Лі
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.