Adakah yang punya saran tentang cara paling efisien untuk menerapkan logika "perbarui baris jika ada orang lain yang menyisipkan" menggunakan Entity Framework?
Adakah yang punya saran tentang cara paling efisien untuk menerapkan logika "perbarui baris jika ada orang lain yang menyisipkan" menggunakan Entity Framework?
Jawaban:
Jika Anda bekerja dengan objek terlampir (objek dimuat dari instance konteks yang sama) Anda cukup menggunakan:
if (context.ObjectStateManager.GetObjectStateEntry(myEntity).State == EntityState.Detached)
{
context.MyEntities.AddObject(myEntity);
}
// Attached object tracks modifications automatically
context.SaveChanges();
Jika Anda dapat menggunakan pengetahuan apa pun tentang kunci objek, Anda dapat menggunakan sesuatu seperti ini:
if (myEntity.Id != 0)
{
context.MyEntities.Attach(myEntity);
context.ObjectStateManager.ChangeObjectState(myEntity, EntityState.Modified);
}
else
{
context.MyEntities.AddObject(myEntity);
}
context.SaveChanges();
Jika Anda tidak dapat memutuskan keberadaan objek dengan ID Anda, Anda harus memeriksa permintaan pencarian:
var id = myEntity.Id;
if (context.MyEntities.Any(e => e.Id == id))
{
context.MyEntities.Attach(myEntity);
context.ObjectStateManager.ChangeObjectState(myEntity, EntityState.Modified);
}
else
{
context.MyEntities.AddObject(myEntity);
}
context.SaveChanges();
using
blok pendek . Apakah saya tetap bisa meninggalkan konteks dalam memori untuk sementara waktu? Misalnya, selama masa pakai formulir Windows? Saya biasanya mencoba dan membersihkan objek database untuk memastikan beban minimum pada database. Apakah tidak ada masalah menunggu untuk menghancurkan konteks EF saya?
Pada Entity Framework 4.3, ada AddOrUpdate
metode di namespace System.Data.Entity.Migrations
:
public static void AddOrUpdate<TEntity>(
this IDbSet<TEntity> set,
params TEntity[] entities
)
where TEntity : class
yang oleh dokter :
Menambahkan atau memperbarui entitas dengan kunci saat SaveChanges dipanggil. Setara dengan operasi "berani" dari terminologi basis data. Metode ini dapat berguna saat menabur data menggunakan Migrasi.
Untuk menjawab komentar oleh @ Smashing1978 , saya akan menempel bagian yang relevan dari tautan yang disediakan oleh @Colin
Tugas AddOrUpdate adalah memastikan bahwa Anda tidak membuat duplikat saat Anda menyemai data selama pengembangan.
Pertama, itu akan menjalankan kueri dalam database Anda mencari catatan di mana apa pun yang Anda berikan sebagai kunci (parameter pertama) cocok dengan nilai kolom yang dipetakan (atau nilai-nilai) yang disediakan di AddOrUpdate. Jadi ini agak longgar untuk cocok tetapi sangat baik untuk penyemaian data waktu desain.
Lebih penting lagi, jika kecocokan ditemukan maka pembaruan akan memperbarui semua dan membatalkan semua yang tidak ada dalam AddOrUpdate Anda.
Yang mengatakan, saya memiliki situasi di mana saya menarik data dari layanan eksternal dan memasukkan atau memperbarui nilai yang ada dengan kunci primer (dan data lokal saya untuk konsumen hanya baca) - telah menggunakan AddOrUpdate
dalam produksi selama lebih dari 6 bulan sekarang dan seterusnya Sejauh ini tidak ada masalah.
Keajaiban terjadi ketika menelepon SaveChanges()
dan tergantung pada arus EntityState
. Jika entitas memiliki EntityState.Added
, maka akan ditambahkan ke database, jika memiliki EntityState.Modified
, maka akan diperbarui dalam database. Jadi, Anda dapat menerapkan InsertOrUpdate()
metode sebagai berikut:
public void InsertOrUpdate(Blog blog)
{
using (var context = new BloggingContext())
{
context.Entry(blog).State = blog.BlogId == 0 ?
EntityState.Added :
EntityState.Modified;
context.SaveChanges();
}
}
Lebih lanjut tentang EntityState
Jika Anda tidak dapat memeriksa Id = 0
untuk menentukan apakah itu entitas baru atau tidak, periksa jawaban Ladislav Mrnka .
Jika Anda tahu bahwa Anda menggunakan konteks yang sama dan tidak melepaskan entitas apa pun, Anda dapat membuat versi generik seperti ini:
public void InsertOrUpdate<T>(T entity, DbContext db) where T : class
{
if (db.Entry(entity).State == EntityState.Detached)
db.Set<T>().Add(entity);
// If an immediate save is needed, can be slow though
// if iterating through many entities:
db.SaveChanges();
}
db
tentu saja bisa menjadi bidang kelas, atau metode ini dapat dibuat statis dan ekstensi, tetapi ini adalah dasar-dasarnya.
Jawaban Ladislav sudah dekat tetapi saya harus membuat beberapa modifikasi agar ini dapat bekerja di EF6 (database-first). Saya memperluas konteks data saya dengan metode AddOrUpdate saya dan sejauh ini tampaknya berfungsi baik dengan objek terpisah:
using System.Data.Entity;
[....]
public partial class MyDBEntities {
public void AddOrUpdate(MyDBEntities ctx, DbSet set, Object obj, long ID) {
if (ID != 0) {
set.Attach(obj);
ctx.Entry(obj).State = EntityState.Modified;
}
else {
set.Add(obj);
}
}
[....]
Menurut pendapat saya, perlu untuk mengatakan bahwa dengan EntityGraphOperations yang baru dirilis untuk Kode Kerangka Kerja Entitas Pertama, Anda dapat menyelamatkan diri dari menulis beberapa kode berulang untuk menentukan status semua entitas dalam grafik. Saya adalah penulis produk ini. Dan saya telah menerbitkannya di github , proyek kode ( termasuk demonstrasi langkah demi langkah dan proyek sampel siap untuk diunduh) dan nuget .
Ini akan secara otomatis mengatur status entitas ke Added
atau Modified
. Dan Anda akan secara manual memilih entitas mana yang harus dihapus jika tidak ada lagi.
Contoh:
Katakanlah saya sudah mendapatkan Person
objek. Person
dapat memiliki banyak telepon, Dokumen dan dapat memiliki pasangan.
public class Person
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string MiddleName { get; set; }
public int Age { get; set; }
public int DocumentId {get; set;}
public virtual ICollection<Phone> Phones { get; set; }
public virtual Document Document { get; set; }
public virtual PersonSpouse PersonSpouse { get; set; }
}
Saya ingin menentukan status semua entitas yang termasuk dalam grafik.
context.InsertOrUpdateGraph(person)
.After(entity =>
{
// Delete missing phones.
entity.HasCollection(p => p.Phones)
.DeleteMissingEntities();
// Delete if spouse is not exist anymore.
entity.HasNavigationalProperty(m => m.PersonSpouse)
.DeleteIfNull();
});
Seperti yang Anda ketahui, properti kunci unik dapat berperan saat menentukan status entitas Telepon. Untuk tujuan khusus seperti itu, kita memiliki ExtendedEntityTypeConfiguration<>
kelas, yang merupakan warisan dari EntityTypeConfiguration<>
. Jika kita ingin menggunakan konfigurasi khusus seperti itu maka kita harus mewarisi dari kelas pemetaan kita ExtendedEntityTypeConfiguration<>
, bukan EntityTypeConfiguration<>
. Sebagai contoh:
public class PhoneMap: ExtendedEntityTypeConfiguration<Phone>
{
public PhoneMap()
{
// Primary Key
this.HasKey(m => m.Id);
…
// Unique keys
this.HasUniqueKey(m => new { m.Prefix, m.Digits });
}
}
Itu saja.
Sisipkan yang lain perbarui keduanya
public void InsertUpdateData()
{
//Here TestEntities is the class which is given from "Save entity connection setting in web.config"
TestEntities context = new TestEntities();
var query = from data in context.Employee
orderby data.name
select data;
foreach (Employee details in query)
{
if (details.id == 1)
{
//Assign the new values to name whose id is 1
details.name = "Sanjay";
details. Surname="Desai";
details.address=" Desiwadi";
}
else if(query==null)
{
details.name="Sharad";
details.surname=" Chougale ";
details.address=" Gargoti";
}
}
//Save the changes back to database.
context.SaveChanges();
}
Periksa baris yang ada dengan Apa saja.
public static void insertOrUpdateCustomer(Customer customer)
{
using (var db = getDb())
{
db.Entry(customer).State = !db.Customer.Any(f => f.CustomerId == customer.CustomerId) ? EntityState.Added : EntityState.Modified;
db.SaveChanges();
}
}
Alternatif untuk jawaban @LadislavMrnka. Ini jika untuk Entity Framework 6.2.0.
Jika Anda memiliki DbSet
item spesifik dan yang perlu diperbarui atau dibuat:
var name = getNameFromService();
var current = _dbContext.Names.Find(name.BusinessSystemId, name.NameNo);
if (current == null)
{
_dbContext.Names.Add(name);
}
else
{
_dbContext.Entry(current).CurrentValues.SetValues(name);
}
_dbContext.SaveChanges();
Namun ini juga dapat digunakan untuk generik DbSet
dengan kunci primer tunggal atau kunci primer komposit.
var allNames = NameApiService.GetAllNames();
GenericAddOrUpdate(allNames, "BusinessSystemId", "NameNo");
public virtual void GenericAddOrUpdate<T>(IEnumerable<T> values, params string[] keyValues) where T : class
{
foreach (var value in values)
{
try
{
var keyList = new List<object>();
//Get key values from T entity based on keyValues property
foreach (var keyValue in keyValues)
{
var propertyInfo = value.GetType().GetProperty(keyValue);
var propertyValue = propertyInfo.GetValue(value);
keyList.Add(propertyValue);
}
GenericAddOrUpdateDbSet(keyList, value);
//Only use this when debugging to catch save exceptions
//_dbContext.SaveChanges();
}
catch
{
throw;
}
}
_dbContext.SaveChanges();
}
public virtual void GenericAddOrUpdateDbSet<T>(List<object> keyList, T value) where T : class
{
//Get a DbSet of T type
var someDbSet = Set(typeof(T));
//Check if any value exists with the key values
var current = someDbSet.Find(keyList.ToArray());
if (current == null)
{
someDbSet.Add(value);
}
else
{
Entry(current).CurrentValues.SetValues(value);
}
}
Dikoreksi
public static void InsertOrUpdateRange<T, T2>(this T entity, List<T2> updateEntity)
where T : class
where T2 : class
{
foreach(var e in updateEntity)
{
context.Set<T2>().InsertOrUpdate(e);
}
}
public static void InsertOrUpdate<T, T2>(this T entity, T2 updateEntity)
where T : class
where T2 : class
{
if (context.Entry(updateEntity).State == EntityState.Detached)
{
if (context.Set<T2>().Any(t => t == updateEntity))
{
context.Set<T2>().Update(updateEntity);
}
else
{
context.Set<T2>().Add(updateEntity);
}
}
context.SaveChanges();
}