Varlık çerçevesinde eklenen varlık kimliğini nasıl edinebilirim? [kapalı]


611

Asp.net'teki Entity Framework ile ilgili bir sorunum var. Veritabanına her nesne eklediğimde id değerini almak istiyorum. Bunu nasıl yapabilirim?


16
Aşağıdaki Ladislav Mrnka'nın cevabı doğru cevaptır ve bu şekilde kabul edilmelidir.
CShark

3
OP, hesabıyla sadece bir kez yayınlandı, bu soru daha spesifik olacak. Bu ona neredeyse 2k ün kazandı (!), Cevap o günden beri hesabın terk edildiği için kabul edilmiş olarak işaretlenmiyor.
MurariAlex

1
Yabancı bir anahtar ilişkisinde kullanmak için kimliğe ihtiyacınız varsa, bunun yerine yalnızca bağımlı varlığınızın navigasyon özelliğini daha önce eklenen varlığa ayarlamayı düşünebilirsiniz. Bu şekilde, SaveChangessadece kimliği almak için hemen arama yapma zahmetine gerek kalmaz . Burada daha fazla okuma .
B12Toaster

Entity Framework Core 3.0 için acceptAllChangesOnSuccess parametresini true olarak ekleyin: await _context.SaveChangesAsync (true);
Mike

Yanıtlar:


1006

Oldukça kolay. DB tarafından oluşturulan Ids ( IDENTITYMS SQL gibi ) kullanıyorsanız, sadece ilgili ObjectSetve SaveChangesilgili varlık eklemeniz gerekir ObjectContext. Idsizin için otomatik olarak doldurulacaktır:

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

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

Varsayılan olarak Varlık çerçeve her aşağıda INSERTile SELECT SCOPE_IDENTITY()otomatik oluşturulan zaman Idler kullanılmaktadır.


34
Yani yanlış soru soruyorsun. İstisna ile ilgili bir sorununuz varsa, istisnanızı (ve iç istisnayı) ve bu hataya neden olan kod snippet'inizi gösteren bir soru sormalısınız.
Ladislav Mrnka

3
Eklediğiniz Varlığın geçerli bir Varlık olduğundan emin olun. Örneğin, "boş olmayan" veritabanı kısıtlaması olan her şey doldurulmalıdır vb.
fran

4
@LadislavMrnka: Yeni oluşturulan nesnenin gezinme özellikleri ne olacak? Değişiklikleri kaydettikten sonra otomatik olarak dolduruluyor gibi görünmüyorlar.
Isaac Kleinman

4
Şu senaryoyu ele alalım: table1'in, table2'de kullanmak için bir @@ kimliği üretmesi gerekiyor. Tablo1 ve tablo2'nin aynı işlemde olduğu varsayılır, örneğin bir SaveChange işlemi her iki tablonun verilerini de kaydetmelidir. 'SaveChanges' çağrılmadığı sürece @@ kimliği oluşturulmaz. bu durumu nasıl ele alabiliriz?
Arash

7
@Djeroen: Veritabanı tarafından oluşturulan kimlik kullanırsanız, önce bu nesneleri veritabanına eklemeniz gerekir. Eklemeden önce Ids olması gerekiyorsa, veri eklenmeden önce benzersiz Ids almak için kendi mantığınızı oluşturmanız gerekir ve veritabanında kimlik sütunu kullanmayın.
Ladislav Mrnka

124

Varlık Çerçevesini kullanırken Lads Mrnka'nın cevabını başarılı bir şekilde almak için kullanıyordum, ancak burada gönderiyorum çünkü özlüyorum (yani gerekli olmadığı yerde kullanıyorum) ve bulgularımı buraya göndereceğimi düşündüm. insanlar yaşadığım sorunu "çözmek" istiyorlar.

Müşteri ile yabancı anahtar ilişkisi olan bir Order nesnesini düşünün. Yeni bir müşteri ve aynı zamanda yeni bir sipariş eklediğimde böyle bir şey yapıyordum;

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

Ancak benim durumumda bu gerekli değildi çünkü müşteri.Id ve order.CustomerId arasında yabancı bir anahtar ilişkim vardı

Tek yapmam gereken buydu;

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

Şimdi değişiklikleri kaydettiğimde müşteri için oluşturulan kimlik de siparişe ekleniyor. Ek adımlara ihtiyacım yok

Bunun orijinal soruya cevap vermediğinin farkındayım, ancak EF için yeni olan geliştiricilere, gerekli olmayabilecek bir şey için en çok oy alan cevabı aşırı kullanmaları konusunda yardımcı olabileceğini düşündüm.

Bu aynı zamanda güncellemelerin tek bir işlemde tamamlandığı anlamına gelir ve potansiyel veriyi önler (ya tüm güncellemeler tamamlanır ya da hiçbiri yapılmaz).


8
Teşekkürler ! ÖNEMLİ En İyi Uygulama İpucu: var order = new Order {Customer = customer}; Bu, Entity Framework'ün ilgili nesneyi atama gücünü gösterir ve Kimlik otomatik olarak güncellenir.
LA Guy 88

Cevaba ek bilgi için teşekkürler. EF kullanırken bir DB gidiş dönüş kaydetme çok yararlı oldu.
Prasad Korhale

Bunun için çok teşekkür ederim. Tam da aradığım şey buydu. Ben sadece iki kez "SaveChanges" çağırmak daha iyi bir yol olabilir inanıyordu
Josh

1
Lütfen cevabınızda (tercihen kalın harflerle) bunun bir işlem davranışını çözdüğünü de belirtin. Nesnelerden biri eklenemezse, işlemin bir kısmı başarılı olmaz. Kişi ve öğrenci ekleme. Kişi başarılı olur ve öğrenci başarısız olur. Şimdi kişi gereksiz. Yine de bu harika çözüm için teşekkürler!
Imran Faruqi

32

Değişiklikleri kaydettikten sonra varlığı yeniden yüklemeniz gerekir. Çünkü EF tarafından izlenemeyen bir veritabanı tetikleyicisi tarafından değiştirilmiştir. Öyleyse varlığı DB'den yeniden yüklememiz gerekiyor,

db.Entry(MyNewObject).GetDatabaseValues();

Sonra

int id = myNewObject.Id;

Aşağıdaki soruda @jayantha cevabına bakınız:

DefaultValue kullanırken eklenen varlık kimliğini Entity çerçevesinde nasıl edinebilirim?

Aşağıdaki soruda @christian yanıtını aramak da yardımcı olabilir:

Varlık Çerçevesi Yenileme bağlamı?


2
Merhaba, bunu yaptığımda, derleme derleme hatası alıyorum: örneğin kimliği veya adı gibi özellikleri çözemiyorum, lütfen bana yardımcı olabilir misiniz?
Morteza Azizi

1
@MortezaAzizi İşlenmemiş veya null özellik sorununun bir hatası gibi görünüyor, ancak daha fazla kod parçacığı açıklayabilir veya yazabilir misiniz?
QMaster

3
.GetDatabaseValues();Modelinizi DB'ye kaydettiyseniz bunu yapmanıza gerek yoktur . Kimlik, modele otomatik olarak yeniden yerleştirilmelidir.
vapcguy

3
@QMaster EF, aynı SQL deyimini de çalıştırabilir (ve uygulayabilir) ve nesnenizin kimliğini doldurur. Aksi takdirde, birden fazla bağımlı nesneyi aynı anda nasıl kaydedebilirim? GetDatabaseValues()Veritabanında aranacak nesnenin kimliğini bilmiyorsa nasıl olur ?
krillgar

2
@vapcguy Anlıyorum. Heeds'in için teşekkürler. Bunu her iki EF ASAP sürümünde de kontrol edeceğim.
QMaster

16

Lütfen bu bağlantıya bakın.

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

StoreGeneratedPattern özelliğini kimliğe ayarlamanız ve ardından kendi kodunuzu denemeniz gerekir.

Yoksa bunu da kullanabilirsiniz.

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

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

7
En çok oy alan cevapla aynı.
Lewis86

2
StoreGeneratedPatternbenim için eksik olan parça.
BurnsBA

1
ORACLE ve ON-Insert Trigger ile çalışırken gitmenin yolu bu,
Karl

bağlantı bozuk - park edilmiş alan adı
t.durden

Merhaba Oracle ile Varlık StoreGeneratedPattern ayarlamak zorunda - model görüntüleyici gidin, tablonuzu ve PK bulmak, StoreGeneratedPattern özelliği seçin ve Kimlik olarak ayarlayın. Yukarıdaki yanıtın gösterdiği gibi çalışır. Bu, PK'nizi kesici uçtaki bir diziden dolduran bir tetikleyicinizin olduğu durum içindir.
Rob


6

Kimliği yalnızca kaydettikten sonra alabilirsiniz, bunun yerine yeni bir Rehber oluşturabilir ve kaydetmeden önce atayabilirsiniz.


4

Ben veritabanına veri eklemek gerekir ve aynı anda varlık çerçevesini kullanarak birincil kimlik gerektiren bir durumla karşılaşıyorum. Çözüm :

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

Tüm cevaplar kendi senaryoları için çok uygundur, farklı yaptığım, int PK'yi doğrudan Add () gibi bir int değişkenine döndürülen nesneden (TEntity) atamasıdır;

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
}

bu yüzden tamamen yeni bir nesne oluşturmak yerine, istediğinizi alırsınız :)

Mr. @GertArnold için DÜZENLE:

resim açıklamasını buraya girin


3
Kimlik atamak için açıklanmayan bir yöntem eklemek gerçekten yararlı değildir. Bu, Entity Framework ile bile ilgili değil.
Gert Arnold

1
@GertArnold .. ben OP ile aynı soru vardı i cevapları buldum ve tek bir satır ifadesine yaptı ve ben açıklamak için yöntem açıklamak hiç terim duymadım açıklamak için?
IteratioN7T

3
Bu, yaptığınız her şeyi göstermediğiniz (ifşa etmediğiniz) anlamına gelir. Belki de açıkça tanımlanmamıştır, bilmiyorum. Ne anlarım ki Add(bu eğer DbSet.Add) yok değil sihirli bir değer atamak EmployeeId.
Gert Arnold

3
Olmadan olmaz SaveChanges. İmkansız. Atanan başka bir işleminiz yoksa EmployeeId, örneğin Employeeyapıcıda. VEYA EF çekirdeğini kullanıyorsunuz ForSqlServerUseSequenceHiLo. Her neyse, tüm resmi vermiyorsun.
Gert Arnold

3
Son sözüm şu olacak: Bu standart EF davranışı değil. Ortamınız hakkında daha fazla ayrıntı vermelisiniz. EF sürümü, veritabanı markası ve sürümü, Çalışan sınıfı, haritalama detayları.
Gert Arnold

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

Bu çalışacak.


4
Depo, değişiklikleri veritabanına kaydetmekle sorumlu değildir. Bu bir UnitOfWork'un işi.
17:55

5
Dahası, ne Repositoryolduğu kesinlikle belli değil . Ve "bu işe yarayacak" bazı açıklama !.
Gert Arnold

2

İki strateji vardır:

  1. Veritabanı tarafından üretilen ID( intveya GUID)

    Eksileri:

    Sadece kaydedilmiş varlıkları SaveChanges()almak için gerçekleştirmelisiniz ID.

    Artıları:

    intKimlik kullanabilir .

  2. İstemci tarafından oluşturulan ID- yalnızca GUID kullanın .

    Artıları: Operasyonların küçültülmesi SaveChanges. Bir işlem başına yeni nesnelerin büyük bir grafiğini ekleyebilir.

    Eksileri:

    Yalnızca GUID


1

Önce EF 6.x kodunu kullandığınızda

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

ve bir veritabanı tablosu başlatmak, bir

(newsequentialid())

Tablo özelliklerinin içinde, Varsayılan Değer veya Bağlama başlığı altında, kimliğin eklenirken doldurulmasına olanak tanır.

Sorun, bir tablo oluşturup tabloyu

[DatabaseGenerated(DatabaseGeneratedOption.Identity)]

bölüm sonra, gelecekteki güncelleme veritabanları (newsequentialid ())

Doğru yolu düzeltmek için geçişi silmek, veritabanını silmek ve yeniden taşımaktır ... ya da sadece tablo tasarımcısına (newsequentialid ()) ekleyebilirsiniz.


Newsequentialid () 'in nereye gittiğini açıklayabilir misiniz? Zaten el ile oluşturulan, ilk önce EF kodu kullanarak veritabanı modelleri var ve bu benim birincil anahtar olmadığı için kimliği doldurmaz. Bunun için çözüm bulmayı çok isterim.
Josh

1
@josh Önce kodun Kılavuz türü olduğunu varsayarsak, Sql Server Management Studio'da tablonuza sağ tıklayın, Id sütununa tıklayın ve Sütun Özellikleri sekmesinin altında (Genel) içinde Varsayılan Değer veya Bağlama göreceksiniz. El ile DB tabloları oluşturuyorsanız, NewSequentialId veya NewId'ye bakın . Genel kullanım durumu şöylewhen -column- is NULL, then NEWID()
Jeff Li
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.