Aracılığıyla paylaş


ExecuteUpdate ve ExecuteDelete

Dekont

Bu özellik EF Core 7.0'da kullanıma sunulmuştur.

ExecuteUpdate ve ExecuteDelete EF'nin geleneksel değişiklik izleme ve SaveChanges() yöntemini kullanmadan verileri veritabanına kaydetmenin bir yoludur. Bu iki tekniğin giriş niteliğindeki karşılaştırması için veri kaydetmeye ilişkin Genel Bakış sayfasına bakın.

Executedelete

Derecelendirmesi belirli bir eşiğin altında olan tüm Blogları silmeniz gerektiğini varsayalım. Geleneksel SaveChanges() yaklaşım için aşağıdakileri yapmanız gerekir:

foreach (var blog in context.Blogs.Where(b => b.Rating < 3))
{
    context.Blogs.Remove(blog);
}

context.SaveChanges();

Bu, bu görevi gerçekleştirmenin oldukça verimsiz bir yoludur: Filtremizle eşleşen tüm Bloglar için veritabanını sorgular ve ardından tüm bu örnekleri sorgular, gerçekleştirir ve izleriz; eşleşen varlıkların sayısı çok büyük olabilir. Ardından EF'in değişiklik izleyicisine her Blog'un kaldırılması gerektiğini söyler ve çağrısı SaveChanges()yaparak bu değişiklikleri uygularız. Bu da her biri için bir DELETE deyim oluşturur.

API aracılığıyla gerçekleştirilen aynı görev aşağıda verilmiştir ExecuteDelete :

context.Blogs.Where(b => b.Rating < 3).ExecuteDelete();

Bu, hangi Blogların nasıl sorgulandığı gibi etkilenmesi gerektiğini belirlemek için tanıdık LINQ işleçlerini kullanır ve ARDıNDAN EF'e veritabanına karşı bir SQL DELETE yürütmesini söyler:

DELETE FROM [b]
FROM [Blogs] AS [b]
WHERE [b].[Rating] < 3

Bu, daha basit ve kısa olmasının yanı sıra, veritabanından veri yüklemeden veya EF'nin değişiklik izleyicisini içermeden veritabanında çok verimli bir şekilde yürütülür. Silmek istediğiniz Blogları seçmek için rastgele LINQ işleçleri kullanabileceğinizi unutmayın. Bunlar, aynı bu Blogları sorguladığınız gibi veritabanında yürütülmek üzere SQL'e çevrilir.

Executeupdate

Bu Blogları silmek yerine, bir özelliği değiştirip bunların gizlenmesi gerektiğini belirtmek istersek ne olur? ExecuteUpdate bir SQL UPDATE deyimini ifade etmek için benzer bir yol sağlar:

context.Blogs
    .Where(b => b.Rating < 3)
    .ExecuteUpdate(setters => setters.SetProperty(b => b.IsVisible, false));

ile ExecuteDeleteolduğu gibi, hangi Blogların etkilenmesi gerektiğini belirlemek için ilk olarak LINQ kullanırız, ancak bununla birlikte ExecuteUpdate eşleşen Bloglara uygulanacak değişikliği de ifade etmemiz gerekir. Bu, çağrının içinde çağrı SetProperty yapılarak ve iki bağımsız değişken sağlanarak yapılır: değiştirilecek özellik (IsVisible) ve sahip olması gereken yeni değer (false).ExecuteUpdate Bu, aşağıdaki SQL'in yürütülmesine neden olur:

UPDATE [b]
SET [b].[IsVisible] = CAST(0 AS bit)
FROM [Blogs] AS [b]
WHERE [b].[Rating] < 3

Birden çok özelliği güncelleştirme

ExecuteUpdate tek bir çağrıda birden çok özelliğin güncelleştirilmesini sağlar. Örneğin, hem false hem de IsVisible sıfır olarak ayarlamak Rating için ek SetProperty çağrıları birbirine zincirlemeniz yeterlidir:

context.Blogs
    .Where(b => b.Rating < 3)
    .ExecuteUpdate(setters => setters
        .SetProperty(b => b.IsVisible, false)
        .SetProperty(b => b.Rating, 0));

Bu işlem aşağıdaki SQL'i yürütür:

UPDATE [b]
SET [b].[Rating] = 0,
    [b].[IsVisible] = CAST(0 AS bit)
FROM [Blogs] AS [b]
WHERE [b].[Rating] < 3

Mevcut özellik değerine başvurma

Yukarıdaki örnekler özelliği yeni bir sabit değere güncelleştirdi. ExecuteUpdate ayrıca yeni değeri hesaplarken var olan özellik değerine başvurmaya izin verir; örneğin, eşleşen tüm Blogların derecelendirmesini bir artırmak için aşağıdakileri kullanın:

context.Blogs
    .Where(b => b.Rating < 3)
    .ExecuteUpdate(setters => setters.SetProperty(b => b.Rating, b => b.Rating + 1));

için ikinci bağımsız değişkenin SetProperty artık bir lambda işlevi olduğunu ve önceki gibi sabit olmadığını unutmayın. Parametresi b güncelleştirilen Blogu temsil eder; bu lambda içinde, b.Rating bu nedenle herhangi bir değişiklik gerçekleşmeden önce derecelendirmeyi içerir. Bu işlem aşağıdaki SQL'i yürütür:

UPDATE [b]
SET [b].[Rating] = [b].[Rating] + 1
FROM [Blogs] AS [b]
WHERE [b].[Rating] < 3

ExecuteUpdate şu anda lambda içindeki gezintilere başvurmayı SetProperty desteklememektedir. Örneğin, tüm Blogların derecelendirmelerini güncelleştirmek istediğimizi ve böylece her Blogun yeni derecelendirmesinin tüm Gönderilerinin derecelendirmelerinin ortalaması olduğunu varsayalım. Şu şekilde kullanmayı ExecuteUpdate deneyebiliriz:

context.Blogs.ExecuteUpdate(
    setters => setters.SetProperty(b => b.Rating, b => b.Posts.Average(p => p.Rating)));

Ancak EF, önce ortalama derecelendirmeyi hesaplamak ve bunu anonim bir türe yansıtmak için kullanarak ve ardından bunu kullanarak ExecuteUpdate bu işlemin Select gerçekleştirilmesine izin verir:

context.Blogs
    .Select(b => new { Blog = b, NewRating = b.Posts.Average(p => p.Rating) })
    .ExecuteUpdate(setters => setters.SetProperty(b => b.Blog.Rating, b => b.NewRating));

Bu işlem aşağıdaki SQL'i yürütür:

UPDATE [b]
SET [b].[Rating] = CAST((
    SELECT AVG(CAST([p].[Rating] AS float))
    FROM [Post] AS [p]
    WHERE [b].[Id] = [p].[BlogId]) AS int)
FROM [Blogs] AS [b]

Değişiklik izleme

Tanıdık SaveChanges kullanıcılar birden çok değişiklik yapmak için kullanılır ve ardından tüm bu değişiklikleri veritabanına uygulamak için çağrı SaveChanges yapar; bu, EF'nin bu değişiklikleri biriken veya izleyen değişiklik izleyicisi tarafından mümkün hale getirilir.

ExecuteUpdate ve ExecuteDelete oldukça farklı çalışırlar: çağrıldıkları noktada hemen etkili olurlar. Bu, tek ExecuteUpdate bir veya ExecuteDelete işlemin birçok satırı etkileyebileceği halde, bu tür birden çok işlemi biriktirip aynı anda uygulamak mümkün olmadığı anlamına gelir; örneğin çağrılırken SaveChanges. Aslında, işlevler EF'in değişiklik izleyicisinin tamamen farkında değildir ve onunla herhangi bir etkileşime sahip değildir. Bunun birkaç önemli sonucu vardır.

Aşağıdaki kodu inceleyin:

// 1. Query the blog with the name `SomeBlog`. Since EF queries are tracking by default, the Blog is now tracked by EF's change tracker.
var blog = context.Blogs.Single(b => b.Name == "SomeBlog");

// 2. Increase the rating of all blogs in the database by one. This executes immediately.
context.Blogs.ExecuteUpdate(setters => setters.SetProperty(b => b.Rating, b => b.Rating + 1));

// 3. Increase the rating of `SomeBlog` by two. This modifies the .NET `Rating` property and is not yet persisted to the database.
blog.Rating += 2;

// 4. Persist tracked changes to the database.
context.SaveChanges();

Önemli ölçüde, çağrıldığında ve veritabanındaki tüm Bloglar güncelleştirildiğinde ExecuteUpdate , EF'nin değişiklik izleyicisi güncelleştirilmez ve izlenen .NET örneğinin sorgulandığı noktadan itibaren özgün derecelendirme değeri hala vardır. Blog'un derecelendirmesinin başlangıçta 5 olduğunu varsayalım; 3. satır yürütüldikten sonra veritabanındaki derecelendirme 6 olur (nedeniyle ExecuteUpdate), ancak izlenen .NET örneğindeki derecelendirme 7 olur. Çağrıldığında SaveChanges EF, 7 yeni değerinin özgün değer 5'ten farklı olduğunu algılar ve bu değişikliği devam ettirer. tarafından ExecuteUpdate gerçekleştirilen değişikliğin üzerine yazılır ve dikkate alınmaz.

Sonuç olarak, aracılığıyla hem izlenen SaveChanges değişiklikleri hem de izlenmeyen değişiklikleri ExecuteUpdate/ExecuteDeletekarıştırmaktan kaçınmak genellikle iyi bir fikirdir.

Hareketler

Yukarıdakilere devam edersek, çağrıldıkları bir işlemi örtük olarak başlatmadıklarını ve anlamaları ExecuteUpdateExecuteDelete önemlidir. Aşağıdaki kodu inceleyin:

context.Blogs.ExecuteUpdate(/* some update */);
context.Blogs.ExecuteUpdate(/* another update */);

var blog = context.Blogs.Single(b => b.Name == "SomeBlog");
blog.Rating += 2;
context.SaveChanges();

Her ExecuteUpdate çağrı veritabanına tek bir SQL UPDATE gönderilmesine neden olur. Hiçbir işlem oluşturulmadığı için, herhangi bir hata türü ikincinin ExecuteUpdate başarıyla tamamlanmasını engellerse, ilkinin etkileri veritabanında kalıcı olmaya devam eder. Aslında yukarıdaki dört işlem - iki çağrısı ExecuteUpdate, bir sorgu ve SaveChanges - her biri kendi işlemi içinde yürütülür. Tek bir işlemdeki birden çok işlemi sarmak için ile DatabaseFacadeaçıkça bir işlem başlatın:

using (var transaction = context.Database.BeginTransaction())
{
    context.Blogs.ExecuteUpdate(/* some update */);
    context.Blogs.ExecuteUpdate(/* another update */);

    ...
}

İşlem işleme hakkında daha fazla bilgi için bkz . İşlemleri Kullanma.

Eşzamanlılık denetimi ve etkilenen satırlar

SaveChangesotomatik Eşzamanlılık Denetimi sağlar ve bir satırın yüklediğiniz an ile değişiklikleri kaydettiğiniz an arasında değiştirilmediğinden emin olmak için eşzamanlılık belirteci kullanılır. ExecuteUpdate Değişiklik izleyicisi ile etkileşim kurmadıkları ve ExecuteDelete etkileşimde bulunmadıkları için otomatik olarak eşzamanlılık denetimi uygulayamazlar.

Ancak, bu yöntemlerin her ikisi de işlemden etkilenen satır sayısını döndürür; Bu, eşzamanlılık denetimini kendiniz uygulamak için özellikle kullanışlı olabilir:

// (load the ID and concurrency token for a Blog in the database)

var numUpdated = context.Blogs
    .Where(b => b.Id == id && b.ConcurrencyToken == concurrencyToken)
    .ExecuteUpdate(/* ... */);
if (numUpdated == 0)
{
    throw new Exception("Update failed!");
}

Bu kodda, belirli bir Bloga güncelleştirme uygulamak için LINQ Where işlecini kullanırız ve yalnızca eşzamanlılık belirtecinin belirli bir değeri varsa (örneğin, blogu veritabanından sorgularken gördüğümüz değer). Ardından tarafından gerçekte kaç satırın güncelleştirildiğini ExecuteUpdatedenetleyeceğiz; sonuç sıfırsa, hiçbir satır güncelleştirilmemiştir ve eşzamanlı güncelleştirme sonucunda eşzamanlılık belirteci büyük olasılıkla değişmiştir.

Sınırlamalar

  • Şu anda yalnızca güncelleştirme ve silme desteklenmektedir; ekleme işlemi ve SaveChanges()aracılığıyla DbSet<TEntity>.Add yapılmalıdır.
  • SQL UPDATE ve DELETE deyimleri etkilenen satırlar için özgün sütun değerlerinin alınmasına izin verse de, bu şu anda ve ExecuteDeletetarafından ExecuteUpdate desteklenmemektedir.
  • Bu yöntemlerin birden çok çağrısı toplu işlenemez. Her çağrı veritabanına kendi gidiş dönüşünü gerçekleştirir.
  • Veritabanları genellikle UPDATE veya DELETE ile yalnızca tek bir tablonun değiştirilmesine izin verir.
  • Bu yöntemler şu anda yalnızca ilişkisel veritabanı sağlayıcılarıyla çalışır.

Ek kaynaklar