Saya mengambil data film dari API eksternal. Pada fase pertama saya akan mengikis setiap film dan memasukkannya ke dalam database saya sendiri. Pada tahap kedua saya akan memperbarui basis data saya secara berkala dengan menggunakan API "Perubahan" API yang dapat saya minta untuk melihat film apa yang informasinya diubah.
Lapisan ORM saya adalah Entity-Framework. Kelas Film terlihat seperti ini:
class Movie
{
public virtual ICollection<Language> SpokenLanguages { get; set; }
public virtual ICollection<Genre> Genres { get; set; }
public virtual ICollection<Keyword> Keywords { get; set; }
}
Masalah muncul ketika saya memiliki film yang perlu diperbarui: database saya akan menganggap objek yang dilacak dan yang baru yang saya terima dari panggilan API pembaruan sebagai objek yang berbeda, mengabaikan .Equals()
.
Ini menyebabkan masalah karena ketika saya sekarang mencoba untuk memperbarui database dengan film yang diperbarui, itu akan memasukkannya daripada memperbarui Film yang ada.
Saya memiliki masalah ini sebelumnya dengan bahasa dan solusi saya adalah untuk mencari objek bahasa yang dilampirkan, melepaskan mereka dari konteks, memindahkan PK mereka ke objek yang diperbarui dan melampirkannya ke konteks. KapanSaveChanges()
sekarang dieksekusi, pada dasarnya akan menggantinya.
Ini adalah pendekatan yang agak bau karena jika saya melanjutkan pendekatan ini ke saya Movie
objek , itu berarti saya harus melepaskan film, bahasa, genre dan kata kunci, mencari masing-masing dalam database, mentransfer ID mereka dan memasukkan benda baru.
Apakah ada cara untuk melakukan ini dengan lebih elegan? Idealnya saya hanya ingin meneruskan film yang diperbarui ke konteks dan memilih film yang benar untuk diperbarui berdasarkan Equals()
metode, memperbarui semua bidangnya dan untuk setiap objek yang kompleks: gunakan catatan yang ada lagi berdasarkan pada sendiriEquals()
metode dan masukkan jika itu belum ada.
Saya dapat melewati detaching / attaching dengan memberikan .Update()
metode pada setiap objek kompleks yang dapat saya gunakan dalam kombinasi mengambil semua objek yang dilampirkan tetapi ini masih akan mengharuskan saya untuk mengambil setiap objek yang ada untuk kemudian memperbaruinya.
sumber
id
dan film dari API eksternal dicocokkan dengan yang lokal menggunakan bidangtmdbid
. Saya tidak dapat mengambil semua entitas yang perlu diperbarui dalam satu panggilan karena ini tentang film, genre, bahasa, kata kunci, dll. Masing-masing memiliki PK dan mungkin sudah ada dalam database.Jawaban:
Saya tidak menemukan apa yang saya harapkan tetapi saya menemukan perbaikan atas urutan select-detach-update-attach yang ada.
Metode ekstensi
AddOrUpdate(this DbSet)
memungkinkan Anda untuk melakukan apa yang ingin saya lakukan: Masukkan jika tidak ada dan perbarui jika menemukan nilai yang ada. Saya tidak menyadari menggunakan ini lebih cepat karena saya benar-benar hanya melihatnya digunakan dalamseed()
metode dalam kombinasi dengan Migrasi. Jika ada alasan saya tidak boleh menggunakan ini, beri tahu saya.Sesuatu yang berguna untuk dicatat: Ada kelebihan yang tersedia yang memungkinkan Anda memilih secara khusus bagaimana kesetaraan harus ditentukan. Di sini saya bisa menggunakan saya
TMDbId
tetapi saya memilih untuk mengabaikan ID saya sendiri dan menggunakan PK pada TMDbId yang dikombinasikanDatabaseGeneratedOption.None
. Saya menggunakan pendekatan ini pada setiap subkoleksi juga, jika perlu.Bagian yang menarik dari sumber :
begitulah data sebenarnya diperbarui di bawah tenda.
Semua yang tersisa memanggil
AddOrUpdate
setiap objek yang saya ingin terpengaruh oleh ini:Ini tidak sebersih yang saya harapkan karena saya harus secara manual menentukan setiap bagian dari objek saya yang perlu diperbarui tapi itu sedekat yang akan didapat.
Bacaan terkait: /programming/15336248/entity-framework-5-updating-a-record
Memperbarui:
Ternyata tes saya tidak cukup ketat. Setelah menggunakan teknik ini saya perhatikan bahwa sementara bahasa baru ditambahkan, itu tidak terhubung ke film. di tabel banyak ke banyak. Ini adalah masalah yang diketahui tetapi tampaknya prioritas rendah dan belum diperbaiki sejauh yang saya tahu.
Pada akhirnya saya memutuskan untuk pergi ke pendekatan di mana saya memiliki
Update(T)
metode pada setiap jenis dan mengikuti urutan peristiwa ini:Update()
metode untuk memperbaruinya dengan nilai-nilai baruIni banyak pekerjaan manual dan jelek jadi itu akan melalui beberapa refactoring lagi tapi sekarang tes saya menunjukkan itu harus bekerja untuk skenario yang lebih ketat.
Setelah membersihkannya lebih lanjut saya sekarang menggunakan metode ini:
Ini memungkinkan saya untuk menyebutnya seperti ini dan menyisipkan / memperbarui koleksi yang mendasarinya:
Perhatikan bagaimana saya menetapkan kembali nilai yang diambil ke objek root asli: sekarang terhubung ke setiap objek yang dilampirkan. Memperbarui objek root (film) dilakukan dengan cara yang sama:
sumber
Karena Anda berurusan dengan bidang yang berbeda
id
dantmbid
, saya sarankan memperbarui API untuk membuat indeks tunggal dan terpisah dari semua info seperti genre, bahasa, kata kunci dll ... Dan kemudian membuat panggilan untuk mengindeks dan memeriksa info daripada mengumpulkan seluruh info tentang objek spesifik di kelas Film Anda.sumber