Not
Bu sayfaya erişim yetkilendirme gerektiriyor. Oturum açmayı veya dizinleri değiştirmeyi deneyebilirsiniz.
Bu sayfaya erişim yetkilendirme gerektiriyor. Dizinleri değiştirmeyi deneyebilirsiniz.
DbContext örneği, veritabanından döndürülen varlıkları otomatik olarak izler. Daha sonra SaveChanges çağrıldığında bu varlıklarda yapılan değişiklikler algılanır ve veritabanı gerektiği gibi güncelleştirilir. Ayrıntılar için bkz. Temel Kaydetme ve İlgili Veriler .
Ancak, bazen varlıklar bir bağlam örneği kullanılarak sorgulanır ve sonra farklı bir örnek kullanılarak kaydedilir. Bu durum genellikle varlıkların sorgulandığı, istemciye gönderildiği, değiştirildiği, istekte sunucuya geri gönderildiği ve ardından kaydedildiği bir web uygulaması gibi "bağlantısız" senaryolarda gerçekleşir. Bu durumda, ikinci bağlam örneğinin varlıkların yeni mi (eklenmelidir) yoksa var mı (güncelleştirilmelidir) olduğunu bilmesi gerekir.
Tavsiye
Bu makalenin örneğini GitHub'da görüntüleyebilirsiniz.
Tavsiye
EF Core, belirli bir birincil anahtar değerine sahip herhangi bir varlığın yalnızca bir örneğini izleyebilir. Bu sorunun oluşmasını önlemenin en iyi yolu, her çalışma birimi için bağlamın boş başlayıp, varlıkların buna eklenip kaydedileceği ve ardından bağlamın sonlandırılıp imha edileceği kısa ömürlü bir bağlam kullanmaktır.
Yeni varlıkları tanımlama
İstemci yeni varlıkları tanımlar
Ele alınacak en basit durum, istemcinin varlığın yeni mi yoksa var mı olduğunu sunucuya bildirmesidir. Örneğin, yeni varlık ekleme isteği genellikle var olan bir varlığı güncelleştirme isteğinden farklıdır.
Bu bölümün geri kalanı, eklenip eklenmeyeceğini veya güncelleştirilip güncelleştirilmeyeceğini başka bir şekilde belirlemenin gerekli olduğu durumları kapsar.
Otomatik oluşturulan anahtarlarla
Otomatik olarak oluşturulan anahtarın değeri genellikle bir varlığın eklenmesi veya güncelleştirilmesi gerekip gerekmediğini belirlemek için kullanılabilir. Anahtar ayarlanmamışsa (yani, hala null, sıfır vb. CLR varsayılan değerine sahipse), varlığın yeni olması ve eklenmesi gerekir. Öte yandan anahtar değeri ayarlanmışsa, daha önce kaydedilmiş olması ve şimdi güncelleştirilmesi gerekir. Başka bir deyişle anahtarın bir değeri varsa varlık sorgulanır, istemciye gönderilir ve güncelleştirilmek üzere geri gelir.
Varlık türü bilindiğinde, ayar yapılmamış bir anahtarı kontrol etmek kolaydır.
public static bool IsItNew(Blog blog)
=> blog.BlogId == 0;
Bununla birlikte, EF'in bunu herhangi bir varlık türü ve anahtar türü için yapmak için yerleşik bir yolu da vardır:
public static bool IsItNew(DbContext context, object entity)
=> !context.Entry(entity).IsKeySet;
Tavsiye
Anahtarlar, varlıklar bağlam tarafından izlenmeye başlanır başlamaz ayarlanır, varlık Eklendi durumunda olsa dahi. Bu, varlıkların grafiğinden geçiş yaparken ve TrackGraph API'sini kullanırken olduğu gibi her biriyle ne yapacağına karar verirken yardımcı olur. Anahtar değeri yalnızca varlığı izlemek için herhangi bir çağrı yapılmadan önce burada gösterilen şekilde kullanılmalıdır.
Diğer tuşlarla
Anahtar değerleri otomatik olarak oluşturulmadığında yeni varlıkları tanımlamak için başka bir mekanizma gerekir. Bunun iki genel yaklaşımı vardır:
- Varlığı sorgula
- İstemciden bayrak gönderme
Varlığı sorgulamak için Find yöntemini kullanmanız yeter:
public static async Task<bool> IsItNew(BloggingContext context, Blog blog)
=> (await context.Blogs.FindAsync(blog.BlogId)) == null;
İstemciden bir bayrak iletmeye yönelik tam kodu göstermek bu belgenin kapsamının dışındadır. Bir web uygulamasında genellikle farklı eylemler için farklı talepler oluşturmak veya istekte bir durum gönderip daha sonra kontrol aygıtında ayıklamak anlamına gelir.
Tekil varlıkları kaydetme
Ekleme veya güncelleştirme gerekip gerekmediği biliniyorsa, Ekle veya Güncelleştir uygun şekilde kullanılabilir:
public static async Task Insert(DbContext context, object entity)
{
context.Add(entity);
await context.SaveChangesAsync();
}
public static async Task Update(DbContext context, object entity)
{
context.Update(entity);
await context.SaveChangesAsync();
}
Ancak varlık otomatik olarak oluşturulan anahtar değerlerini kullanıyorsa Update yöntemi her iki durumda da kullanılabilir:
public static async Task InsertOrUpdate(DbContext context, object entity)
{
context.Update(entity);
await context.SaveChangesAsync();
}
Update yöntemi normalde varlığı ekleme için değil güncelleştirme için işaretler. Ancak, varlığın otomatik olarak oluşturulan bir anahtarı varsa ve hiçbir anahtar değeri ayarlanmamışsa, varlık bunun yerine otomatik olarak ekleme için işaretlenir.
Varlık otomatik olarak oluşturulan anahtarları kullanmıyorsa, uygulamanın varlığın eklenip eklenmeyeceğine veya güncelleştirileceğine karar vermesi gerekir: Örneğin:
public static async Task InsertOrUpdate(BloggingContext context, Blog blog)
{
var existingBlog = await context.Blogs.FindAsync(blog.BlogId);
if (existingBlog == null)
{
context.Add(blog);
}
else
{
context.Entry(existingBlog).CurrentValues.SetValues(blog);
}
await context.SaveChangesAsync();
}
Buradaki adımlar şunlardır:
- Eğer Find null döndürürse, veritabanı bu kimliğe sahip blogu zaten içermez, bu nedenle, eklenmek üzere işaretlemek için Add'i çağırırız.
- Bul bir varlık döndürürse, veritabanında var olur ve bağlam artık var olan varlığı izliyor demektir
- Ardından, bu varlık üzerindeki tüm özelliklerin değerlerini istemciden gelenlere ayarlamak için SetValues kullanırız.
- SetValues çağrısı, varlığı gerektiğinde güncellenecek şekilde işaretler.
Tavsiye
SetValues yalnızca izlenen varlıktakilerle farklı değerlere sahip olan özellikleri değiştirilmiş olarak işaretler. Bu, güncelleştirme gönderildiğinde yalnızca gerçekten değiştirilmiş olan sütunların güncelleştirileceği anlamına gelir. (Hiçbir şey değişmediyse hiçbir güncelleştirme gönderilmez.)
Grafiklerle çalışma
Kimlik çözümlemesi
Yukarıda belirtildiği gibi EF Core, belirli bir birincil anahtar değerine sahip herhangi bir varlığın yalnızca bir örneğini izleyebilir. Graflarla çalışırken, graf ideal olarak bu sabitin korunacağı şekilde oluşturulmalıdır ve bağlam yalnızca bir çalışma birimi için kullanılmalıdır. Graf yinelenenler içeriyorsa, birden çok örneği tek bir örnekte birleştirmek için grafı EF'ye göndermeden önce işlemek gerekir. Örneklerin çakışan değerlere ve ilişkilere sahip olması önemsiz olmayabilir, bu nedenle çakışma çözümlemesini önlemek için yinelenenleri birleştirme işlemi uygulama işlem hattınızda mümkün olan en kısa sürede yapılmalıdır.
Tüm yeni/tüm mevcut varlıklar
Grafiklerle çalışma örneği, ilişkili gönderi koleksiyonuyla birlikte bir blog eklemek veya güncelleştirmektir. Grafikteki tüm varlıkların eklenmesi veya tümünün güncelleştirilmesi gerekiyorsa, işlem yukarıda tek varlıklar için açıklananla aynıdır. Örneğin, aşağıdaki gibi oluşturulan blogların ve gönderilerin grafiği:
var blog = new Blog
{
Url = "http://sample.com", Posts = new List<Post> { new Post { Title = "Post 1" }, new Post { Title = "Post 2" }, }
};
şu şekilde eklenebilir:
public static async Task InsertGraph(DbContext context, object rootEntity)
{
context.Add(rootEntity);
await context.SaveChangesAsync();
}
Ekle çağrısı blogu ve eklenecek tüm gönderileri işaretler.
Benzer şekilde, bir grafikteki tüm varlıkların güncelleştirilmiş olması gerekiyorsa Update kullanılabilir:
public static async Task UpdateGraph(DbContext context, object rootEntity)
{
context.Update(rootEntity);
await context.SaveChangesAsync();
}
Blog ve tüm gönderileri güncellenmek üzere işaretlenecek.
Yeni ve mevcut varlıkların karışımı
Otomatik oluşturulan anahtarlarla, grafik ekleme gerektiren varlıkların bir karışımını ve güncelleştirilmesini gerektiren varlıkların bir karışımını içerse bile Güncelleştirme, hem eklemeler hem de güncelleştirmeler için yeniden kullanılabilir:
public static async Task InsertOrUpdateGraph(DbContext context, object rootEntity)
{
context.Update(rootEntity);
await context.SaveChangesAsync();
}
Güncelleme, grafik, blog veya gönderideki herhangi bir varlığın anahtar değeri ayarlanmamışsa, bu varlık ekleme için işaretlenirken; anahtar değeri ayarlanmış olan diğer tüm varlıklar güncelleme için işaretlenir.
Daha önce olduğu gibi, otomatik oluşturulan anahtarları kullanmadığınızda bir sorgu ve bazı işlemler kullanılabilir:
public static async Task InsertOrUpdateGraph(BloggingContext context, Blog blog)
{
var existingBlog = await context.Blogs
.Include(b => b.Posts)
.FirstOrDefaultAsync(b => b.BlogId == blog.BlogId);
if (existingBlog == null)
{
context.Add(blog);
}
else
{
context.Entry(existingBlog).CurrentValues.SetValues(blog);
foreach (var post in blog.Posts)
{
var existingPost = existingBlog.Posts
.FirstOrDefault(p => p.PostId == post.PostId);
if (existingPost == null)
{
existingBlog.Posts.Add(post);
}
else
{
context.Entry(existingPost).CurrentValues.SetValues(post);
}
}
}
await context.SaveChangesAsync();
}
Silme işlemlerini yönetme
Silme işleminin işlenmesi zor olabilir çünkü çoğu durumda varlığın olmaması, varlığın silinmesi gerektiği anlamına gelir. Bununla başa çıkmanın bir yolu, varlığın aslında silinmek yerine silinmiş olarak işaretlenmesi için "geçici silmeleri" kullanmaktır. Silme işlemleri sonrasında güncellemelerle aynı hale gelir. Geçici silme işlemleri sorgu filtreleri kullanılarak uygulanabilir.
Gerçek silmeler için yaygın bir desen, temelde bir grafik farkını gerçekleştirmek için sorgu deseninin bir uzantısını kullanmaktır. Örneğin:
public static async Task InsertUpdateOrDeleteGraph(BloggingContext context, Blog blog)
{
var existingBlog = await context.Blogs
.Include(b => b.Posts)
.FirstOrDefaultAsync(b => b.BlogId == blog.BlogId);
if (existingBlog == null)
{
context.Add(blog);
}
else
{
context.Entry(existingBlog).CurrentValues.SetValues(blog);
foreach (var post in blog.Posts)
{
var existingPost = existingBlog.Posts
.FirstOrDefault(p => p.PostId == post.PostId);
if (existingPost == null)
{
existingBlog.Posts.Add(post);
}
else
{
context.Entry(existingPost).CurrentValues.SetValues(post);
}
}
foreach (var post in existingBlog.Posts)
{
if (!blog.Posts.Any(p => p.PostId == post.PostId))
{
context.Remove(post);
}
}
}
await context.SaveChangesAsync();
}
TrackGraph
Dahili olarak, Ekle, Bağla ve Güncelleştir, her varlık için eklenmiş (eklemek için), değiştirilmiş (güncellemek için), değişmemiş (hiçbir şey yapmamak) veya silinmiş (silmek için) olarak işaretlenmesi gereken bir belirleme ile graf gezintisi kullanır. Bu mekanizma, TrackGraph API'sini kullanarak kullanıma sunulur. Örneğin, istemci varlıkların grafiğini geri gönderdiğinde her varlıkta nasıl işleneceğini belirten bir bayrak ayarlandığını varsayalım. TrackGraph daha sonra bu bayrağı işlemek için kullanılabilir:
public static async Task SaveAnnotatedGraph(DbContext context, object rootEntity)
{
context.ChangeTracker.TrackGraph(
rootEntity,
n =>
{
var entity = (EntityBase)n.Entry.Entity;
n.Entry.State = entity.IsNew
? EntityState.Added
: entity.IsChanged
? EntityState.Modified
: entity.IsDeleted
? EntityState.Deleted
: EntityState.Unchanged;
});
await context.SaveChangesAsync();
}
Bayraklar yalnızca örneğin basitliği için varlığın bir parçası olarak gösterilir. Bayraklar genellikle bir DTO'nun parçası veya isteğe dahil edilen başka bir durumun parçası olur.