Bagaimana saya bisa mendapatkan Id entitas yang dimasukkan dalam kerangka kerja Entity? [Tutup]

611

Saya memiliki masalah dengan Kerangka Entitas di Asp.net. Saya ingin mendapatkan nilai Id setiap kali saya menambahkan objek ke database. Bagaimana saya bisa melakukan ini?

ahmet
sumber
16
Jawaban oleh Ladislav Mrnka di bawah adalah jawaban yang benar, dan harus diterima.
CShark
3
OP hanya memposting sekali dengan akunnya, pertanyaan ini lebih spesifik. Ini memberinya hampir 2k dalam reputasi (!), Jawabannya tidak ditandai sebagai diterima karena akun ditinggalkan sejak hari itu.
MurariAlex
1
Jika Anda hanya perlu ID untuk menggunakannya dalam hubungan kunci asing, Anda dapat mempertimbangkan hanya mengatur properti navigasi entitas tergantung Anda ke entitas yang ditambahkan sebelumnya. Dengan cara ini Anda tidak perlu repot-repot menelepon SaveChangeslangsung hanya untuk mendapatkan id. Bacaan lebih lanjut di sini .
B12Toaster
Untuk Entity Framework Core 3.0, tambahkan parameter acceptAllChangesOnSuccess sebagai true: await _context.SaveChangesAsync (true);
Mike

Jawaban:

1006

Ini sangat mudah. Jika Anda menggunakan DB yang dihasilkan Id (seperti IDENTITYdalam MS SQL) Anda hanya perlu menambahkan entitas ke ObjectSetdan SaveChangespada yang terkait ObjectContext. Idakan secara otomatis diisi untuk Anda:

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

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

Kerangka kerja entitas secara default mengikuti masing INSERT- masing dengan SELECT SCOPE_IDENTITY()ketika Ids dihasilkan otomatis digunakan.

Ladislav Mrnka
sumber
34
Jadi, Anda mengajukan pertanyaan yang salah. Jika Anda memiliki masalah dengan pengecualian, Anda harus mengajukan pertanyaan yang menunjukkan pengecualian Anda (dan pengecualian dalam) dan potongan kode yang menyebabkan kesalahan itu.
Ladislav Mrnka
3
Pastikan bahwa Entitas yang Anda tambahkan adalah Entitas yang valid, mis., Apa pun dengan batasan basis data "tidak nol" harus diisi dll.
fran
4
@LadislavMrnka: Bagaimana dengan properti navigasi dari objek yang baru dibuat? Mereka sepertinya tidak secara otomatis terisi setelah menyimpan perubahan.
Isaac Kleinman
4
Mari kita pertimbangkan skenario berikut: table1 seharusnya menghasilkan identitas @@ untuk menggunakannya di table2. Baik table1 dan table2 seharusnya dalam transaksi yang sama untuk misalnya satu operasi SaveChange harus menyimpan data kedua tabel. @@ identitas tidak akan dihasilkan kecuali jika 'SaveChanges' dipanggil. bagaimana kita mengatasi situasi ini?
Arash
7
@ Djeroen: Jika Anda menggunakan ID yang dihasilkan database, Anda harus terlebih dahulu memasukkan objek-objek itu ke database. Jika Anda harus memiliki Id sebelum penyisipan, Anda harus membangun logika Anda sendiri untuk mendapatkan Id unik sebelum data dimasukkan dan tidak menggunakan kolom identitas dalam database.
Ladislav Mrnka
124

Saya telah menggunakan jawaban Ladislav Mrnka untuk berhasil mengambil Id ketika menggunakan Entity Framework namun saya memposting di sini karena saya telah salah menggunakannya (yaitu menggunakannya di tempat yang tidak diperlukan) dan berpikir saya akan memposting temuan saya di sini di- jika orang mencari untuk "memecahkan" masalah yang saya miliki.

Pertimbangkan objek Pesanan yang memiliki hubungan kunci asing dengan Pelanggan. Ketika saya menambahkan pelanggan baru dan pesanan baru pada saat yang sama saya melakukan sesuatu seperti ini;

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

Namun dalam kasus saya ini tidak diperlukan karena saya memiliki hubungan kunci asing antara pelanggan. Id dan pesanan. Pelanggan

Yang harus saya lakukan adalah ini;

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

Sekarang ketika saya menyimpan perubahan, id yang dibuat untuk pelanggan juga ditambahkan ke pesanan. Saya tidak perlu untuk langkah-langkah tambahan

Saya sadar ini tidak menjawab pertanyaan awal tetapi berpikir itu mungkin membantu pengembang yang baru mengenal EF dari menggunakan terlalu banyak jawaban terpilih untuk sesuatu yang mungkin tidak diperlukan.

Ini juga berarti bahwa pembaruan selesai dalam satu transaksi tunggal, berpotensi menghindari data orphin (baik semua pembaruan selesai, atau tidak ada yang dilakukan).

mark_h
sumber
8
Terima kasih! Kiat Praktik Terbaik PENTING: var order = Pesanan baru {Pelanggan = pelanggan}; Ini menunjukkan kekuatan Entity Framework untuk menetapkan objek terkait dan Id akan secara otomatis diperbarui.
LA Guy 88
Terima kasih atas informasi tambahan ini untuk jawabannya. Sangat membantu dalam menyimpan pulang pergi DB saat menggunakan EF.
Prasad Korhale
Terima kasih banyak atas ini. Inilah yang saya cari. Saya hanya percaya mungkin ada cara yang lebih baik daripada memanggil "SaveChanges" dua kali
Josh
1
Harap sebutkan juga dalam jawaban Anda (terutama dalam huruf tebal) bahwa ini menyelesaikan perilaku transaksi. Jika salah satu objek gagal ditambahkan, bagian dari transaksi tidak akan berhasil. Misalnya, Menambahkan orang dan siswa. Orang berhasil dan siswa gagal. Sekarang orang itu mubazir. Terima kasih atas solusi hebat ini!
Imran Faruqi
32

Anda harus memuat ulang entitas setelah menyimpan perubahan. Karena telah diubah oleh pemicu basis data yang tidak dapat dilacak oleh EF. SO kita perlu memuat kembali entitas dari DB,

db.Entry(MyNewObject).GetDatabaseValues();

Kemudian

int id = myNewObject.Id;

Lihatlah jawaban @jayantha dalam pertanyaan di bawah ini:

Bagaimana saya bisa mendapatkan Id entitas yang dimasukkan dalam kerangka Entity saat menggunakan defaultValue?

Mencari jawaban Kristen di pertanyaan di bawah ini juga dapat membantu:

Kerangka Entitas Segarkan konteks?

QMaster
sumber
2
Hai, ketika saya suka ini, saya mendapatkan kesalahan kompilasi yang mengatakan: tidak dapat menyelesaikan properti misalnya Id atau Nama, bisakah Anda membantu saya?
Morteza Azizi
1
@MortezaAzizi Tampaknya ada kesalahan karena tidak menangani atau tidak memiliki masalah properti, tetapi bisakah Anda lebih menjelaskan atau menulis beberapa cuplikan kode?
QMaster
3
Seharusnya tidak harus dilakukan .GetDatabaseValues();jika Anda baru saja menyimpan model Anda ke DB. ID harus terisi kembali ke model secara otomatis.
vapcguy
3
@QMaster Kecuali EF juga mampu (dan tidak) menjalankan pernyataan SQL yang sama dan mengisi ID objek Anda. Jika tidak, bagaimana cara menyimpan banyak objek dependen pada saat yang bersamaan? Bagaimana bisa GetDatabaseValues()jika tidak tahu ID objek yang akan dicari dalam database?
krillgar
2
@vapcguy saya mengerti. Terima kasih atas perhatian Anda. Saya akan memeriksa itu di kedua versi EF ASAP.
QMaster
16

Silakan merujuk tautan ini.

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

Anda harus mengatur properti StoreGeneratedPattern ke identitas dan kemudian coba kode Anda sendiri.

Atau Anda juga bisa menggunakan ini.

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

  int id = myNewObject.Id; // Your Identity column ID
}
Azhar Mansuri
sumber
7
Sama seperti jawaban terpilih teratas.
Lewis86
2
StoreGeneratedPatternadalah bagian yang hilang untuk saya.
BurnsBA
1
Itulah cara yang harus ditempuh ketika bekerja dengan ORACLE dan Pemicu Sisipan-ON,
Karl
tautan rusak - domain terparkir
t.durden
Halo dengan Oracle, saya harus mengatur StoreGeneratedPattern di Entity - buka model viewer, cari tabel dan PK Anda, pilih properti StoreGeneratedPattern dan atur ke Identity. Ini berfungsi seperti yang ditunjukkan oleh jawaban di atas. Ini untuk kasus di mana Anda memiliki pemicu yang mengisi PK Anda dari urutan pada masukkan.
Rob
15

Objek yang Anda simpan harus memiliki yang benar Idsetelah menyebarkan perubahan ke dalam basis data.

Snowbear
sumber
27
Pernahkah Anda melihat pengecualian batiniah? ;-)
Snowbear
6

Anda bisa mendapatkan ID hanya setelah menyimpan, sebagai gantinya Anda dapat membuat Guid baru dan menetapkan sebelum menyimpan.

Vaduganathan Pillappan
sumber
4

Saya menemukan situasi di mana saya perlu memasukkan data dalam database & secara bersamaan memerlukan id primer menggunakan kerangka entitas. Solusi:

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

Semua jawaban sangat cocok untuk skenario mereka sendiri, yang saya lakukan berbeda adalah bahwa saya menetapkan int PK langsung dari objek (TEntity) yang Tambah () kembali ke variabel int seperti ini;

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
}

jadi alih-alih membuat keseluruhan objek baru, Anda hanya mengambil apa yang Anda inginkan :)

EDIT Untuk Tn. @GertArnold:

masukkan deskripsi gambar di sini

IteratioN7T
sumber
3
Tidak terlalu berguna untuk menambahkan metode yang tidak diungkapkan untuk menetapkan ID. Ini bahkan tidak terkait dengan Kerangka Entitas.
Gert Arnold
1
@GertArnold .. saya punya pertanyaan yang sama dengan OP saya menemukan jawaban dan membuatnya menjadi pernyataan garis tunggal, dan saya belum pernah mendengar istilah metode yang diungkapkan untuk peduli?
IteratioN7T
3
Itu hanya berarti bahwa Anda tidak menunjukkan (mengungkapkan) semua yang Anda lakukan. Mungkin tidak dijelaskan dengan jelas, saya tidak tahu. Yang saya tahu adalah bahwa Add(jika ini DbSet.Add) tidak secara ajaib memberikan nilai EmployeeId.
Gert Arnold
3
Bukan tanpa SaveChanges. Mustahil. Kecuali Anda memiliki beberapa proses lain yang ditugaskan EmployeeId, misalnya dalam Employeekonstruktor. ATAU Anda menggunakan inti EF ForSqlServerUseSequenceHiLo. Bagaimanapun, Anda tidak memberikan gambaran keseluruhan.
Gert Arnold
3
Komentar terakhir saya adalah: ini bukan perilaku EF standar. Anda harus memberikan rincian lebih lanjut tentang lingkungan Anda. Versi EF, merek dan versi database, kelas Karyawan, detail pemetaannya.
Gert Arnold
3
Repository.addorupdate(entity, entity.id);
Repository.savechanges();
Var id = entity.id;

Ini akan bekerja

Saket Choubey
sumber
4
Repositori tidak bertanggung jawab untuk menyimpan perubahan ke dalam basis data. Ini pekerjaan UnitOfWork.
tchelidze
5
Selain itu, sama sekali tidak jelas apa Repositoryitu. Dan "ini akan berhasil" adalah beberapa penjelasan !.
Gert Arnold
2

Ada dua strategi:

  1. Gunakan Database yang dihasilkan ID(int atau GUID)

    Cons:

    Anda harus melakukan SaveChanges()untuk mendapatkanID entitas yang baru saja disimpan.

    Pro:

    Dapat menggunakan intidentitas.

  2. Gunakan klien yang dihasilkan ID - hanya GUID.

    Pro: Minifikasi SaveChanges operasi. Mampu menyisipkan grafik besar objek baru per satu operasi.

    Cons:

    Hanya diizinkan untuk GUID

Vladislav Furdak
sumber
1

Saat Anda menggunakan kode EF 6.x terlebih dahulu

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

dan menginisialisasi tabel database, itu akan meletakkan

(newsequentialid())

di dalam properti tabel di bawah Nilai Default tajuk atau Binding, memungkinkan ID untuk diisi saat dimasukkan.

Masalahnya adalah jika Anda membuat tabel dan menambahkan

[DatabaseGenerated(DatabaseGeneratedOption.Identity)]

bagian nanti, basis data pembaruan masa depan tidak akan menambah kembali (new followingentialid ())

Untuk memperbaiki cara yang tepat adalah dengan menghapus migrasi, menghapus database dan migrasi kembali ... atau Anda bisa menambahkan (new followingentialid ()) ke dalam desainer tabel.

Jeff Li
sumber
Bisakah Anda menguraikan di mana new berikutnyaentialid () pergi? Saya sudah memiliki model basis data yang dibuat dengan tangan, tidak menggunakan kode EF terlebih dahulu, dan tidak mengisi id karena itu bukan kunci utama saya. Senang mencari solusi untuk itu.
Josh
1
@ josh Menganggap kode pertama adalah tipe Guid, klik kanan tabel Anda di Sql Server Management Studio, klik kolom Id, dan di bawah tab Column Properties, di dalam (Umum), Anda akan melihat Nilai Default atau Binding. Jika Anda membuat tabel DB dengan tangan, lihat NewSequentialId atau NewId . Kasing penggunaan umum adalah sesuatu sepertiwhen -column- is NULL, then NEWID()
Jeff Li