Entity Framework 4 - AddObject vs Attach

132

Saya telah bekerja dengan Entity Framework 4 baru-baru ini, dan saya sedikit bingung kapan harus menggunakan ObjectSet.Attach , dan ObjectSet.AddObject .

Dari pengertian saya:

  • Gunakan "Lampirkan" ketika Entitas sudah ada di sistem
  • Gunakan "AddObject" saat membuat Entitas baru

Jadi, jika saya membuat Orang baru , saya melakukan ini.

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

Jika saya memodifikasi Orang yang ada , saya melakukan ini:

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

Perlu diingat, ini adalah contoh yang sangat sederhana . Pada kenyataannya saya menggunakan Pure POCO (tanpa pembuatan kode), pola Repositori (tidak berurusan dengan ctx.Persons), dan Unit Kerja (jangan berurusan dengan ctx.SaveChanges). Tetapi "di bawah penutup", di atas adalah apa yang terjadi dalam implementasi saya.

Sekarang, pertanyaan saya - saya belum menemukan skenario di mana saya harus menggunakan Lampirkan .

Apa yang kulewatkan di sini? Kapan kita perlu menggunakan Lampirkan?

EDIT

Sekedar klarifikasi, saya sedang mencari contoh kapan harus menggunakan Lampirkan di atas AddObject (atau sebaliknya).

EDIT 2

Jawaban di bawah ini benar (yang saya terima), tetapi saya pikir saya akan menambahkan contoh lain di mana Attach akan berguna.

Dalam contoh saya di atas untuk memodifikasi Orang yang ada , dua pertanyaan sebenarnya sedang dieksekusi.

Satu untuk mengambil Person (.SingleOrDefault), dan satu lagi untuk melakukan UPDATE (.SaveChanges).

Jika (karena alasan tertentu), saya sudah tahu bahwa "Joe Bloggs" ada di sistem, mengapa melakukan permintaan tambahan untuk mendapatkannya terlebih dahulu? Saya bisa melakukan ini:

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

Ini akan menghasilkan hanya pernyataan UPDATE yang dieksekusi.

RPM1984
sumber
Pasang juga digunakan di MVC sekarang hari ketika menempatkan model kembali langsung ke EF. Bekerja dengan sangat baik dan menghemat satu ton baris kode.
Piotr Kula

Jawaban:

162

ObjectContext.AddObject dan ObjectSet.AddObject :
The AddObject metode adalah untuk menambahkan objek baru dibuat yang tidak ada dalam database. Entitas akan mendapatkan EntityKey sementara yang dihasilkan secara otomatisdan EntityState akan diatur ke Ditambahkan . Ketika SaveChanges dipanggil, akan jelas bagi EF bahwa entitas ini perlu dimasukkan ke dalam basis data.

ObjectContext.Attach dan ObjectSet.Attach :
Di sisi lain, Attach digunakan untuk entitas yang sudah ada dalam database. Daripada mengatur EntityState ke Ditambahkan, Lampirkan hasil dalamEntityState Tidak Berubah , yang berarti itu tidak berubah sejak itu melekat pada konteks. Objek yang Anda lampirkan diasumsikan ada di database. Jika Anda memodifikasi objek setelah mereka dilampirkan, ketika Anda memanggil SaveChanges nilai dari EntityKey digunakan untuk memperbarui (atau menghapus) baris yang sesuai dengan menemukan ID yang cocok di tabel db.

Selanjutnya, menggunakan metode Lampirkan, Anda bisa menentukan hubungan antara entitas yang sudah ada di ObjectContext tetapi yang adabelum terhubung secara otomatis. Pada dasarnya tujuan utama Lampirkan, adalah untuk menghubungkan entitas yang sudah dilampirkan ke ObjectContext dan bukan baru sehingga Anda tidak dapat menggunakan Lampirkan untuk melampirkan entitas yang EntityState ditambahkan. Anda harus menggunakan Tambah () dalam kasus ini.

Misalnya, anggap entitas Orang Anda memiliki properti navigasi bernama Alamat yang merupakan kumpulanentitas Alamat . Katakanlah Anda telah membaca kedua Objek dari konteks, tetapi mereka tidak terkait satu sama lain dan Anda ingin membuatnya jadi:

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();
Morteza Manavi
sumber
Terima kasih atas jawabannya, saya mengerti definisi keduanya (alias dua paragraf pertama). Tapi saya tidak mengerti skenario di mana saya PERLU menggunakan Attach. Paragraf terakhir Anda tidak benar-benar masuk akal bagi saya (pada dasarnya membaca seperti kombinasi dari dua paragraf pertama), dapatkah Anda memberi saya contoh di mana saya akan menggunakan "Lampirkan" dalam skenario saya di atas? Itu benar-benar apa yang saya cari - contoh, bukan definisi. Sangat menghargai waktu Anda. :)
RPM1984
1
Tidak masalah, saya telah menambahkan potongan kode untuk memperjelas paragraf terakhir, karena Anda dapat melihat kami memiliki 2 objek yang tidak terkait dan Lampirkan membantu kami untuk menghubungkannya satu sama lain. Contoh lain adalah dengan menggunakan metode Lampirkan () untuk Melampirkan "entitas Terpisah" kembali ke konteks (Ada berbagai alasan bahwa Anda mungkin ingin entitas Terpisah untuk Terlampir kembali ke konteks)
Morteza Manavi
1
Yap, saya mengerti sekarang. Saya baru saja menonton video TechEd di EF4 (oleh Julie Lerman), yang menunjukkan contoh. Anda mungkin memiliki entitas yang TIDAK Anda ambil dari kueri (mis. Itu tidak terhubung), tetapi Anda tahu itu ada, karena itu Anda menggunakan Lampirkan untuk melakukan UPDATE pada entitas itu. Masuk akal, meskipun saya masih berjuang untuk membayangkan skenario di mana Anda akan memiliki entitas "terputus". Terima kasih atas bantuan Anda.
RPM1984
1
Bagus. Dapatkah saya meminta Anda untuk membagikan tautan video kepada sesama pengembang yang mungkin membaca posting ini?
Morteza Manavi
3
Tautan di atas yang dibagikan oleh RPM1984 rusak, sekarang dialihkan ke channel9.msdn.com/Events/TechEd/NorthAmerica/2010/DEV205 . Nikmati
Ditumpuk
31

Ini adalah respons yang terlambat tetapi mungkin membantu orang lain yang menemukan ini.

Pada dasarnya, entitas "terputus" dapat terjadi ketika Anda memanipulasi entitas di luar lingkup "menggunakan".

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
}

Jika Anda memasukkan lingkup "using" yang lain maka variabel "e" akan terputus karena ia termasuk dalam lingkup "using" sebelumnya dan karena lingkup "using" sebelumnya dihancurkan maka "e" terputus.

Begitulah cara saya memahaminya.

TchiYuan
sumber
3
Contoh Tchi adalah contoh yang bagus dan sederhana - ya, variabel Karyawan harus dinyatakan di luar. coba e.Address.Street di luar ruang lingkup dan lihat pop-up pengecualian referensi nol. Jika Anda Melampirkan maka aplikasi tidak harus kembali ke DB untuk Karyawan di lingkup kedua.
Steve
9

Ini adalah kutipan dari Kerangka Kerja Entitas Pemrograman: DbContext

Memanggil Hapus pada entitas yang tidak dilacak oleh konteks akan menyebabkan InvalidOperationException dilempar. Kerangka Entitas melempar pengecualian ini karena tidak jelas apakah entitas yang Anda coba hapus adalah entitas yang sudah ada yang harus ditandai untuk dihapus atau entitas baru yang seharusnya diabaikan saja. Karena alasan ini, kami tidak dapat menggunakan hanya Hapus untuk menandai entitas yang terputus sebagai Dihapus; kita harus melampirkannya terlebih dahulu .

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();
    }
}

Metode TestDeleteDestination mensimulasikan aplikasi klien mengambil Tujuan yang ada dari server dan kemudian meneruskannya ke metode DeleteDestination di server. Metode DeleteDestination menggunakan metode Lampirkan untuk membuat konteks tahu bahwa itu adalah Tujuan yang ada. Kemudian metode Hapus digunakan untuk mendaftarkan Tujuan yang ada untuk dihapus

Teoman shipahi
sumber
-8

Bagaimana dengan hanya merujuk ke kunci utama alih-alih melampirkan?

yaitu:

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();
Dan
sumber