Entity Framework 4 - AddObject vs Attach


132

Geçenlerde İdare Framework 4 ile çalışıyor olması ve biraz ne zaman kullanılacağını olarak karıştı ObjectSet.Attach ve ObjectSet.AddObject .

Anladığım kadarıyla:

  • Sistemde zaten bir Varlık varsa "Ekle" yi kullanın
  • Yepyeni bir Varlık oluştururken "AddObject" kullanın

Yani, yeni bir Kişi oluşturuyorsam , bunu yaparım.

var ctx = new MyEntities();
var newPerson = new Person { Name = "Joe Bloggs" };
ctx.Persons.AddObject(newPerson);
ctx.SaveChanges();

İ olursam varolan Kişi değiştirerek , bunu yapmak:

var ctx = new MyEntities();
var existingPerson = ctx.Persons.SingleOrDefault(p => p.Name = "Joe Bloggs" };
existingPerson.Name = "Joe Briggs";
ctx.SaveChanges();

Unutmayın, bu çok basit bir örnek. Gerçekte, Pure POCO'lar (kod üretme yok), Depo kalıbı (ctx.Persons ile uğraşmayın) ve İş Birimi (ctx.SaveChanges ile uğraşmayın) kullanıyorum. Ancak "örtülerin altında", benim uygulamamda yukarıdakiler oluyor.

Şimdi sorum - Attach'ı kullanmak zorunda olduğum bir senaryoyu henüz bulamadım .

Burada neyi özlüyorum? Attach'ı ne zaman kullanmamız gerekir?

DÜZENLE

Sadece açıklığa kavuşturmak için, AddObject üzerinden Attach (veya tam tersi) ne zaman kullanılacağına dair örnekler arıyorum .

DÜZENLEME 2

Aşağıdaki cevap doğrudur (kabul ettim), ancak Ekle'nin yararlı olacağı başka bir örnek ekleyeceğimi düşündüm.

Mevcut bir Kişiyi değiştirmek için yukarıdaki örneğimde, aslında iki sorgu yürütülüyor.

Kişi (.SingleOrDefault) almak ve diğeri GÜNCELLEME (.SaveChanges) gerçekleştirmek için.

Eğer (herhangi bir nedenle), sistemde "Joe Bloggs" un var olduğunu zaten biliyorsam, neden önce onu almak için fazladan bir sorgu yapayım? Bunu yapabilirim:

var ctx = new MyEntities();
var existingPerson = new Person { Name = "Joe Bloggs" };
ctx.Persons.Attach(existingPerson);
ctx.SaveChanges();

Bu, yalnızca bir UPDATE deyiminin yürütülmesine neden olur.


Ekleme, MVC'de, modelleri doğrudan EF'ye geri koyarken bir gündür de kullanılmaktadır. Oldukça iyi çalışıyor ve tonlarca kod satırı kaydediyor.
Piotr Kula

Yanıtlar:


162

ObjectContext.AddObject ve ObjectSet.AddObject : AddObject yöntemi do yeni oluşturulan nesneler ekleme içindir değil veritabanında mevcut. Varlık, otomatik olarak oluşturulan geçici bir EntityKey alacak ve EntityState öğesi Eklendi olarak ayarlanacaktır. SaveChanges çağrıldığında, bu varlığın veritabanına eklenmesi gerektiği EF için açık olacaktır.

ObjectContext.Attach ve ObjectSet.Attach :
Öte yandan, Attach ,veritabanındazaten var olanvarlıklar için kullanılır. EntityState'i Eklendi olarak ayarlamak yerine, Attach bir Unchanged EntityState ile sonuçlanır, bu da içeriğe eklendiğinden beri değişmediği anlamına gelir. Eklediğiniz nesnelerin veritabanında var olduğu varsayılır. Nesneleri eklendikten sonra değiştirirseniz, SaveChanges'ı çağırdığınızda EntityKey'in değeri, uygun satırı db tablosunda eşleşen kimliğini bularak güncellemek (veya silmek) için kullanılır.

Ayrıca, Attach yöntemini kullanarak, ObjectContext'te zaten var olan ancak aşağıdakilere sahip olan varlıklar arasındaki ilişkileri tanımlayabilirsiniz.değil otomatik bağlandı. Temel olarak, takın temel amacı zaten ObjectContext bağlı? Elde edilen bağlantı kuruluşlara olan değil kimin EntityState Added varlıkları eklemek için Ekle kullanmayın böylece yeni. Bu durumda Add () kullanmanız gerekir.

Örneğin, Kişi varlığınızın bir Adres varlığıkoleksiyonu olan Adresler adlı bir gezinme özelliğine sahip olduğunu varsayalım. Diyelim ki her iki Nesneyi bağlamdan okudunuz, ancak birbirleriyle ilişkili değiller ve siz de öyle yapmak istiyorsunuz:

var existingPerson = ctx.Persons.SingleOrDefault(p => p.Name = "Joe Bloggs" };
var myAddress = ctx.Addresses.First(a => a.PersonID != existingPerson.PersonID);
existingPerson.Addresses.Attach(myAddress);
// OR:
myAddress.PersonReference.Attach(existingPerson)
ctx.SaveChanges();

Cevap için teşekkürler, ikisinin tanımını anlıyorum (diğer bir deyişle ilk iki paragraf). Ama Ekle'yi kullanmam GEREKEN bir senaryo anlamıyorum. Son paragrafınız bana pek mantıklı gelmiyor (temelde ilk iki paragrafın bir kombinasyonu gibi okuyor), yukarıdaki senaryomda "Ekle" yi nerede kullanacağımla ilgili bir örnek verebilir misiniz? Gerçekten aradığım şey bu - örnekler, tanımlar değil. Zaman ayırdığınız için gerçekten minnettarım. :)
RPM1984

1
Sorun değil, son paragrafı açıklığa kavuşturmak için bir kod parçacığı ekledim, görebileceğiniz gibi 2 alakasız nesnemiz var ve Ekle bunları birbirleriyle ilişkilendirmemize yardımcı oluyor. Diğer örnek, "Ayrılmış bir varlığı" bağlama geri eklemek için Attach () yöntemini kullanmak olacaktır (Ayrılmış bir varlığın bağlama geri Eklenmesini istemenizin çeşitli nedenleri vardır)
Morteza Manavi

1
Evet, şimdi anladım. Az önce EF4'te (Julie Lerman tarafından) bir TechEd videosunu izledim, bir örnek. Bir sorgudan ALMADIĞINIZ (yani bağlantısı kesilmiş) bir varlığa sahip olabilirsiniz, ancak var olduğunu biliyorsunuz, bu nedenle bu varlık üzerinde bir GÜNCELLEME gerçekleştirmek için Ekle'yi kullanırsınız. Hala "bağlantısız" bir varlığa sahip olacağınız bir senaryo tasavvur etmekte zorlansam da mantıklı geliyor. Yardımınız için teşekkürler.
RPM1984

1
Harika. Sizden bu gönderiyi okuyabilecek diğer geliştiriciler için videonun bağlantısını paylaşmanızı rica edebilir miyim?
Murtaza Manavi

3
RPM1984 tarafından paylaşılan yukarıdaki bağlantı bozuk, şimdi channel9.msdn.com/Events/TechEd/NorthAmerica/2010/DEV205 adresine yönlendiriliyor . Enjoy
Üst Üste

31

Bu geç bir cevaptır, ancak bunu bulan diğerlerine yardımcı olabilir.

Temel olarak, bir varlığı "kullanma" kapsamının dışında işlediğinizde "bağlantısı kesilmiş" bir varlık meydana gelebilir.

Employee e = null;

using (var ctx = new MyModelContainer())
{
     e = ctx.Employees.SingleOrDefault(emp => emp .....);
}

using (var ctx2 = new MyModelContainer())
{
     e; // This entity instance is disconnected from ctx2
}

Başka bir "kullanan" kapsam girerseniz, "e" değişkeninin bağlantısı kesilir çünkü önceki "kullanma" kapsamına aittir ve önceki "kullanma" kapsamı kaldırıldığı için "e" değişkeni kesilir.

Ben böyle anlıyorum.


3
Tchi'nin örneği mükemmel ve basit bir örnektir - evet, Employee değişkeni dışarıda beyan edilmelidir. e.Address.Street'i kapsam dışında deneyin ve boş referans istisna açılır penceresini görün. Eklerseniz, uygulamanın ikinci kapsamdaki Çalışan için DB'ye geri dönmesi gerekmez.
Steve

9

Bu, Programming Entity Framework'den bir alıntıdır : DbContext

İçerik tarafından izlenmeyen bir varlık üzerinde Kaldır çağrılması, bir InvalidOperationException oluşmasına neden olur. Entity Framework bu istisnayı atar çünkü kaldırmaya çalıştığınız varlığın silinmek üzere işaretlenmesi gereken varolan bir varlık mı yoksa yok sayılması gereken yeni bir varlık mı olduğu açık değildir. Bu nedenle, bağlantısı kesilmiş bir varlığı Silindi olarak işaretlemek için Kaldır'ı kullanamayız; önce onu eklemeliyiz .

private static void TestDeleteDestination()
{
    Destination canyon;
    using (var context = new BreakAwayContext())
    {
        canyon = (from d in context.Destinations
        where d.Name == "Grand Canyon"
        select d).Single();
    }
    DeleteDestination(canyon);
}
private static void DeleteDestination(Destination destination)
{
    using (var context = new BreakAwayContext())
    {
        context.Destinations.Attach(destination);
        context.Destinations.Remove(destination);
        context.SaveChanges();
    }
}

TestDeleteDestination yöntemi, sunucudan mevcut bir Hedefi alan ve ardından bunu sunucudaki DeleteDestination yöntemine geçiren bir istemci uygulamasını simüle eder. DeleteDestination yöntemi, bağlamın var olan bir Hedef olduğunu bilmesini sağlamak için Attach yöntemini kullanır. Ardından, silinmek üzere mevcut Hedefi kaydetmek için Kaldır yöntemi kullanılır.


-8

Eklemek yerine yalnızca birincil anahtara başvurmaya ne dersiniz?

yani:

var existingPerson = ctx.Persons.SingleOrDefault(p => p.Name = "Joe Bloggs" };
var myAddress = ctx.Addresses.First(a => a.PersonID != existingPerson.PersonID);
existingPerson.AddressId = myAddress.Id // not -> existingPerson.Addresses.Attach(myAddress);
// OR:
myAddress.Person.Id = existingPerson.Id // not -> myAddress.PersonReference.Attach(existingPerson);
ctx.SaveChanges();
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.