Entity Framework kullanarak "güncelleme satırı varsa eklemek" mantık uygulamak için en verimli yolu hakkında önerileri var mı?
Entity Framework kullanarak "güncelleme satırı varsa eklemek" mantık uygulamak için en verimli yolu hakkında önerileri var mı?
Yanıtlar:
Ekli nesneyle (içeriğin aynı örneğinden yüklenen nesne) çalışıyorsanız, şunları kullanabilirsiniz:
if (context.ObjectStateManager.GetObjectStateEntry(myEntity).State == EntityState.Detached)
{
context.MyEntities.AddObject(myEntity);
}
// Attached object tracks modifications automatically
context.SaveChanges();
Nesnenin anahtarı hakkında herhangi bir bilgi kullanabiliyorsanız şu şekilde kullanabilirsiniz:
if (myEntity.Id != 0)
{
context.MyEntities.Attach(myEntity);
context.ObjectStateManager.ChangeObjectState(myEntity, EntityState.Modified);
}
else
{
context.MyEntities.AddObject(myEntity);
}
context.SaveChanges();
Nesnenin kimliğiyle varlığına karar veremiyorsanız, arama sorgusunu gerçekleştirmelisiniz:
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
bloğa koyarım. Bağlamı bir süreliğine hafızada bırakmak uygun mudur? Örneğin, bir Windows formunun ömrü boyunca? Normalde veritabanında minimum yük sağlamak için veritabanı nesnelerini temizlemeye çalışırım. EF bağlamımı yok etmeyi bekleyen bir sorun yok mu?
Entity Framework 4.3 itibariyle AddOrUpdate
, ad alanında bir yöntem vardır System.Data.Entity.Migrations
:
public static void AddOrUpdate<TEntity>(
this IDbSet<TEntity> set,
params TEntity[] entities
)
where TEntity : class
hangi doktor tarafından :
SaveChanges çağrıldığında varlıkları anahtarla ekler veya günceller. Veritabanı terminolojisinden "yukarı" bir işleme eşdeğerdir. Bu yöntem, Taşıma İşlemleri kullanarak veri eklerken faydalı olabilir.
@ Smashing1978 tarafından yapılan yorumu cevaplamak için , @Colin tarafından sağlanan bağlantıdan ilgili parçaları yapıştıracağım
AddOrUpdate'in görevi, geliştirme sırasında veri eklediğinizde kopya oluşturmamanızı sağlamaktır.
İlk olarak, veritabanınızda anahtar olarak sağladığınız şeyin (ilk parametre) AddOrUpdate'de sağlanan eşlenmiş sütun değeri (veya değerleri) ile eşleştiği bir kayıt arayan bir sorgu yürütür. Bu, eşleştirme için biraz gevşek, ancak tasarım zamanı verilerini tohumlamak için mükemmel bir şekilde iyi.
Daha da önemlisi, bir eşleşme bulunursa, güncelleme tüm güncellemeleri yapar ve AddOrUpdate'inizde olmayanları geçersiz kılar.
Bununla birlikte, harici bir hizmetten veri çektiğim ve birincil anahtarla (ve tüketiciler için yerel verilerim salt okunur) mevcut değerleri eklediğim veya güncellediğim bir durumum var - AddOrUpdate
6 aydan fazla bir süredir üretimde kullanıyorum ve bu yüzden çok sorun yok.
Sihir çağırırken olur SaveChanges()
ve akıma bağlıdır EntityState
. Varlığın bir EntityState.Added
değeri varsa, veritabanına eklenir, eğer varsa EntityState.Modified
, veritabanında güncellenir. Böylece InsertOrUpdate()
aşağıdaki gibi bir yöntem uygulayabilirsiniz :
public void InsertOrUpdate(Blog blog)
{
using (var context = new BloggingContext())
{
context.Entry(blog).State = blog.BlogId == 0 ?
EntityState.Added :
EntityState.Modified;
context.SaveChanges();
}
}
EntityState hakkında daha fazla bilgi
Eğer kontrol edemiyorsanız Id = 0
yeni bir varlık olduğunu olmadığını belirlemek için, kontrol Ladislav Mrnka cevabını .
Aynı içeriği kullandığınızı ve herhangi bir varlığı ayırmadığınızı biliyorsanız, bunun gibi genel bir sürüm oluşturabilirsiniz:
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
elbette bir sınıf alanı olabilir veya yöntem statik ve bir uzantı yapılabilir, ancak bu temeldir.
Ladislav'un cevabı yakındı ama bunu EF6'da (önce veritabanı) çalıştırmak için birkaç değişiklik yapmak zorunda kaldım. Veri bağlamımı AddOrUpdate yöntemimle genişlettim ve şimdiye kadar bu ayrılmış nesnelerle iyi çalışıyor gibi görünüyor:
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);
}
}
[....]
Kanımca, yeni yayınlanan EntityGraphOperations for Entity Framework Code ile öncelikle grafikteki tüm varlıkların durumlarını tanımlamak için bazı tekrarlayan kodlar yazmaktan kurtulabilirsiniz . Bu ürünün yazarıyım. Ve bunu github'da yayınladım , kod projesi ( adım adım bir gösteri içerir ve örnek bir proje indirilmeye hazır) ve nuget .
Varlıkların durumunu otomatik olarak Added
veya olarak ayarlarModified
. Artık yoksa, hangi varlıkların silinmesi gerektiğini manuel olarak seçeceksiniz.
Örnek:
Diyelim ki bir Person
nesnem var. Person
olabilir birçok telefon, bir belge ve olabilir bir eş.
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; }
}
Grafiğe dahil olan tüm varlıkların durumunu belirlemek istiyorum.
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();
});
Ayrıca bildiğiniz gibi benzersiz anahtar özellikleri Telefon varlık durumunu tanımlarken rol oynayabilir. Böyle özel amaçlar için ExtendedEntityTypeConfiguration<>
miras alan bir sınıfımız var EntityTypeConfiguration<>
. Biz o zaman bizim haritalama sınıfları miras gerekir tür özel yapılandırmaları kullanmak isterseniz ExtendedEntityTypeConfiguration<>
ziyade, EntityTypeConfiguration<>
. Örneğin:
public class PhoneMap: ExtendedEntityTypeConfiguration<Phone>
{
public PhoneMap()
{
// Primary Key
this.HasKey(m => m.Id);
…
// Unique keys
this.HasUniqueKey(m => new { m.Prefix, m.Digits });
}
}
Bu kadar.
Her ikisini de başka güncelleme ekle
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();
}
Herhangi biriyle mevcut satırı kontrol edin.
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();
}
}
@LadislavMrnka yanıtı için alternatif. Bu Varlık Çerçevesi 6.2.0 için ise.
DbSet
Güncellenmesi veya oluşturulması gereken belirli bir öğeniz varsa:
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();
Ancak bu, DbSet
tek bir birincil anahtar veya birleşik birincil anahtar içeren bir jenerik için de kullanılabilir .
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);
}
}
Düzeltilmiş
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();
}