İzlenen Varlıklara Erişme

DbContext tarafından izlenen varlıklara erişim için dört ana API vardır.

Bunların her biri aşağıdaki bölümlerde daha ayrıntılı olarak açıklanmıştır.

Tavsiye

Bu belgede varlık durumlarının ve EF Core değişiklik izlemenin temellerinin anlaşıldığı varsayılır. Bu konular hakkında daha fazla bilgi için bkz. EF Core'da Değişiklik İzleme .

Tavsiye

GitHub'dan örnek kodu indirerek bu belgedeki tüm kodu çalıştırabilir ve hatalarını ayıklayabilirsiniz.

DbContext.Entry ve EntityEntry örneklerini kullanma

Her izlenen varlık için Entity Framework Core (EF Core) şunları izler:

  • Varlığın genel durumu. Bu, Unchanged, Modified, Added veya Deleted'den biridir; daha fazla bilgi için EF Core'da Değişiklik İzleme'ye bakın.
  • İzlenen varlıklar arasındaki ilişkiler. Örneğin, gönderinin ait olduğu blog.
  • Özelliklerin "geçerli değerleri".
  • Özelliklerin "orijinal değerleri", bu bilgi mevcut olduğunda. Özgün değerler, varlık veritabanından sorgulandığında var olan özellik değerleridir.
  • Sorgulandıklarından beri hangi özellik değerleri değiştirildi?
  • Değerin geçici olup olmadığı gibi özellik değerleriyle ilgili diğer bilgiler.

Bir varlık örneğinin geçirilmesi DbContext.Entry , verilen varlık için bu bilgilere erişim sağlanmasına neden EntityEntry<TEntity> olur. Örneğin:

using var context = new BlogsContext();

var blog = await context.Blogs.SingleAsync(e => e.Id == 1);
var entityEntry = context.Entry(blog);

Aşağıdaki bölümlerde varlık durumuna erişmek ve bu durumu işlemek için EntityEntry'nin nasıl kullanılacağı ve varlığın özelliklerinin ve gezintilerinin durumu gösterilmektedir.

Varlık ile çalışmak

EntityEntry<TEntity> öğesinin en yaygın kullanımı, bir varlığın geçerli EntityState'ine erişmektir. Örneğin:

var currentState = context.Entry(blog).State;
if (currentState == EntityState.Unchanged)
{
    context.Entry(blog).State = EntityState.Modified;
}

Entry yöntemi, henüz izlenmemiş varlıklarda da kullanılabilir. Bu , varlığı izlemeye başlamaz; varlığın durumu hala Detachedşeklindedir. Ancak, döndürülen EntityEntry daha sonra varlık durumunu değiştirmek için kullanılabilir ve bu noktada varlık belirtilen durumda izlenir. Örneğin, aşağıdaki kod bir Blog örneğini şu şekilde Addedizlemeye başlar:

var newBlog = new Blog();
Debug.Assert(context.Entry(newBlog).State == EntityState.Detached);

context.Entry(newBlog).State = EntityState.Added;
Debug.Assert(context.Entry(newBlog).State == EntityState.Added);

Tavsiye

EF6'nın aksine, tek bir varlığın durumunu ayarlamak tüm bağlı varlıkların izlenmesine neden olmaz. Bu, durumun bu şekilde ayarlanmasının, bir varlık grafiğinin tamamında çalışan Add, Attach veya Update işlevlerini çağırmaktan daha düşük düzeyli bir işlemdir.

Aşağıdaki tabloda, varlığın tamamıyla çalışmak için EntityEntry kullanmanın yolları özetlenir:

EntityEntry üyesi Açıklama
EntityEntry.State Varlığın EntityState öğesini alır ve ayarlar.
EntityEntry.Entity Varlık örneğini alır.
EntityEntry.Context Bu varlığı izleyen DbContext.
EntityEntry.Metadata IEntityType varlık türü için meta veriler.
EntityEntry.IsKeySet Varlığın anahtar değerinin belirlenip belirlenmediği.
EntityEntry.Reload() Özellik değerlerini veritabanından okunan değerlerle günceller.
EntityEntry.DetectChanges() Yalnızca bu varlık için değişikliklerin algılanmasını zorla; bkz: Değişiklik Algılama ve Bildirimler.

Tek bir özellik üzerinde çalışma

Bir varlığın EntityEntry<TEntity>.Property tek bir özelliği hakkındaki bilgilere erişim sağlamak için çeşitli aşırı yüklemeler mevcuttur. Örneğin, kesin türe sahip, akıcı bir API kullanarak:

PropertyEntry<Blog, string> propertyEntry = context.Entry(blog).Property(e => e.Name);

Bunun yerine özellik adı dize olarak geçirilebilir. Örneğin:

PropertyEntry<Blog, string> propertyEntry = context.Entry(blog).Property<string>("Name");

Döndürülen PropertyEntry<TEntity,TProperty> daha sonra özelliği hakkındaki bilgilere erişmek için kullanılabilir. Örneğin, bu varlık üzerindeki özelliğin geçerli değerini almak ve ayarlamak için kullanılabilir:

string currentValue = context.Entry(blog).Property(e => e.Name).CurrentValue;
context.Entry(blog).Property(e => e.Name).CurrentValue = "1unicorn2";

Yukarıda kullanılan Özellik yöntemlerinin her ikisi de kesin olarak türü belirlenmiş bir genel PropertyEntry<TEntity,TProperty> örnek döndürür. Bu genel türün kullanılması tercih edilir çünkü kutulama değer türleri olmadan özellik değerlerine erişime izin verir. Ancak, derleme zamanında varlık veya özellik türü bilinmiyorsa, bunun yerine genel olmayan bir PropertyEntry elde edilebilir.

PropertyEntry propertyEntry = context.Entry(blog).Property("Name");

Bu, değer türlerini kutulama maliyeti pahasına, türü ne olursa olsun herhangi bir mülkün bilgilerine erişim sağlar. Örneğin:

object blog = await context.Blogs.SingleAsync(e => e.Id == 1);

object currentValue = context.Entry(blog).Property("Name").CurrentValue;
context.Entry(blog).Property("Name").CurrentValue = "1unicorn2";

Aşağıdaki tabloda PropertyEntry tarafından kullanıma sunulan özellik bilgileri özetlemektedir:

PropertyEntry üyesi Açıklama
PropertyEntry<TEntity,TProperty>.CurrentValue Özelliğin geçerli değerini alır ve ayarlar.
PropertyEntry<TEntity,TProperty>.OriginalValue Özelliğin özgün değerini, mevcutsa, alır ve ayarlar.
PropertyEntry<TEntity,TProperty>.EntityEntry Varlık için EntityEntry<TEntity> öğesine geri başvuru.
PropertyEntry.Metadata IProperty özelliği için meta veriler.
PropertyEntry.IsModified Bu özelliğin değiştirilmiş olarak işaretlenip işaretlenmediğini gösterir ve bu durumun değiştirilmesine izin verir.
PropertyEntry.IsTemporary Bu özelliğin geçici olarak işaretlenip işaretlenmediğini gösterir ve bu durumun değiştirilmesine izin verir.

Notlar:

  • Bir özelliğin özgün değeri, varlık veritabanından sorgulandığında özelliğin sahip olduğu değerdir. Ancak, varlığın bağlantısı kesildiyse ve daha sonra Attach veya Update ile başka bir DbContext'e açıkça eklenmişse özgün değerler kullanılamaz. Bu durumda, döndürülen özgün değer geçerli değerle aynı olacaktır.
  • SaveChanges yalnızca değiştirilmiş olarak işaretlenen özellikleri güncelleştirir. EF Core'un belirli bir özellik değerini güncelleştirmesini zorlamak için true olarak ayarlayın IsModified veya EF Core'un özellik değerini güncelleştirmesini önlemek için false olarak ayarlayın.
  • Geçici değerler genellikle EF Core değer oluşturucuları tarafından oluşturulur. Bir özelliğin geçerli değerini ayarlamak geçici değeri verilen değerle değiştirir ve özelliği geçici değil olarak işaretler. Bir değeri açıkça ayarlandıktan sonra bile geçici olmaya zorlamak için true olarak ayarlayın IsTemporary .

Tek bir navigasyonla çalışma

EntityEntry<TEntity>.Reference, EntityEntry<TEntity>.Collection, ve EntityEntry.Navigation aşırı yüklemeleri, tek bir gezintiye ilişkin bilgilere erişime izin verir.

İlgili tek bir varlığa referans gezintileri, Reference yöntemleri aracılığıyla erişilir. Referans navigasyonları, bire çok ilişkilerin "bir" taraflarını ve bire bir ilişkilerin her iki tarafını işaret eder. Örneğin:

ReferenceEntry<Post, Blog> referenceEntry1 = context.Entry(post).Reference(e => e.Blog);
ReferenceEntry<Post, Blog> referenceEntry2 = context.Entry(post).Reference<Blog>("Blog");
ReferenceEntry referenceEntry3 = context.Entry(post).Reference("Blog");

Navigasyonlar, bire çok ve çoka çok ilişkilerinin "çok" tarafları için kullanıldığında, ilgili varlıkların koleksiyonları da olabilir. Collection Yöntemler, koleksiyon gezintilerine erişmek için kullanılır. Örneğin:

CollectionEntry<Blog, Post> collectionEntry1 = context.Entry(blog).Collection(e => e.Posts);
CollectionEntry<Blog, Post> collectionEntry2 = context.Entry(blog).Collection<Post>("Posts");
CollectionEntry collectionEntry3 = context.Entry(blog).Collection("Posts");

Bazı işlemler tüm navigasyonlar için ortaktır. Bunlara, EntityEntry.Navigation yöntemi kullanılarak hem referans hem de koleksiyon gezintileri için erişilebilir. Tüm gezintilere birlikte erişirken yalnızca genel olmayan erişimin kullanılabildiğini unutmayın. Örneğin:

NavigationEntry navigationEntry = context.Entry(blog).Navigation("Posts");

Aşağıdaki tabloda ReferenceEntry<TEntity,TProperty>, CollectionEntry<TEntity,TRelatedEntity>, ve NavigationEntry kullanma yolları özetlenmiştir:

NavigationEntry üyesi Açıklama
MemberEntry.CurrentValue Navigasyonun geçerli değerini alır ve ayarlar. Bu, koleksiyon gezinmelerini kolaylaştıran tüm koleksiyondur.
NavigationEntry.Metadata INavigationBase gezinti meta verileri.
NavigationEntry.IsLoaded İlgili varlığın veya koleksiyonun veritabanından tamamen yüklenip yüklenmediğini belirten bir değer alır veya ayarlar.
NavigationEntry.Load() veritabanından ilgili varlığı veya koleksiyonu yükler; bkz. İlgili Verilerin Açıkça Yüklenmesi.
NavigationEntry.Query() EF Core'in kullanacağı sorgu, bu gezintiyi daha fazla oluşturulmaya uygun bir IQueryable olarak yükler; bkz. İlgili Verilerin Manuel Olarak Yüklenmesi.

Varlığın tüm özellikleriyle çalışma

EntityEntry.Propertiesvarlığın IEnumerable<T> her özelliği için bir PropertyEntry döndürür. Bu, varlığın her özelliği için bir eylem gerçekleştirmek için kullanılabilir. Örneğin, herhangi bir DateTime özelliğini DateTime.Now olarak ayarlamak için:

foreach (var propertyEntry in context.Entry(blog).Properties)
{
    if (propertyEntry.Metadata.ClrType == typeof(DateTime))
    {
        propertyEntry.CurrentValue = DateTime.Now;
    }
}

Ayrıca, EntityEntry tüm özellik değerlerini aynı anda almak ve ayarlamak için çeşitli yöntemler içerir. Bu yöntemler, bir özellik koleksiyonunu ve değerlerini temsil eden sınıfını kullanır PropertyValues . PropertyValues, geçerli veya özgün değerler için veya veritabanında şu anda depolandığı gibi değerler için alınabilir. Örneğin:

var currentValues = context.Entry(blog).CurrentValues;
var originalValues = context.Entry(blog).OriginalValues;
var databaseValues = await context.Entry(blog).GetDatabaseValuesAsync();

Bu PropertyValues nesneleri kendi başlarına çok kullanışlı değildir. Ancak, varlıkları düzenlerken gereken yaygın işlemleri gerçekleştirmek için birleştirilebilirler. Bu, veri aktarımı nesneleriyle çalışırken ve iyimser eşzamanlılık çakışmalarını çözerken kullanışlıdır. Aşağıdaki bölümlerde bazı örnekler gösterilmektedir.

Bir varlıktan veya DTO'dan geçerli veya özgün değerleri ayarlama

Bir varlığın geçerli veya özgün değerleri, başka bir nesneden değerler kopyalanarak güncelleştirilebilir. Örneğin, varlık türüyle aynı özelliklere sahip bir BlogDto veri aktarım nesnesi (DTO) düşünün:

public class BlogDto
{
    public int Id { get; set; }
    public string Name { get; set; }
}

Bu, kullanılarak PropertyValues.SetValuesizlenen bir varlığın geçerli değerlerini ayarlamak için kullanılabilir:

var blogDto = new BlogDto { Id = 1, Name = "1unicorn2" };

context.Entry(blog).CurrentValues.SetValues(blogDto);

Bu teknik bazen bir varlığı bir hizmet çağrısından veya n katmanlı bir uygulamadaki bir istemciden alınan değerlerle güncelleştirirken kullanılır. Kullanılan nesnenin, adları varlığın özellikleriyle eşleşen özelliklere sahip olduğu sürece varlıkla aynı türde olması gerekmediğini unutmayın. Yukarıdaki örnekte, izlenen BlogDto bir varlığın geçerli değerlerini ayarlamak için DTO Blog örneği kullanılmıştır.

Özelliklerin yalnızca değer kümesi geçerli değerden farklıysa değiştirilmiş olarak işaretleneceğini unutmayın.

Sözlükten geçerli veya özgün değerleri ayarlama

Önceki örnek, bir varlık veya DTO örneğinden değerleri ayarlar. Özellik değerleri bir sözlükte ad/değer çiftleri olarak depolandığında da aynı davranış kullanılabilir. Örneğin:

var blogDictionary = new Dictionary<string, object> { ["Id"] = 1, ["Name"] = "1unicorn2" };

context.Entry(blog).CurrentValues.SetValues(blogDictionary);

Veritabanından geçerli veya özgün değerleri ayarlama

Bir varlığın geçerli veya özgün değerleri, veritabanından alınan en yeni değerlerle güncellenebilir. Bunun için GetDatabaseValues() veya GetDatabaseValuesAsync çağrılır ve döndürülen nesne, bu değerlerin geçerli veya özgün olanlarını ayarlamak için kullanılır. Örneğin:

var databaseValues = await context.Entry(blog).GetDatabaseValuesAsync();
context.Entry(blog).CurrentValues.SetValues(databaseValues);
context.Entry(blog).OriginalValues.SetValues(databaseValues);

Geçerli, özgün veya veritabanı değerlerini içeren kopyalanmış nesne oluşturma

CurrentValues, OriginalValues veya GetDatabaseValues'tan döndürülen PropertyValues nesnesi kullanılarak PropertyValues.ToObject() varlığın bir kopyası oluşturulabilir. Örneğin:

var clonedBlog = (await context.Entry(blog).GetDatabaseValuesAsync()).ToObject();

ToObject DbContext tarafından izlenmemiş yeni bir örnek döndürdüğünü unutmayın. Döndürülen nesnenin diğer varlıklarla ayarlanmış hiçbir ilişkisi de yoktur.

Kopyalanan nesne, özellikle belirli bir türdeki nesnelere veri bağlama sırasında veritabanındaki eşzamanlı güncelleştirmeler ile ilgili sorunları çözmek için yararlı olabilir. Daha fazla bilgi için bkz. iyimser eşzamanlılık .

Bir varlığın tüm yönlendirmeleriyle çalışmak

EntityEntry.Navigations, varlığın her gezintisi için bir IEnumerable<T> olarak NavigationEntry döndürür. EntityEntry.References ve EntityEntry.Collections aynı şeyi yapar, ancak sırasıyla başvuru veya koleksiyon gezintileriyle sınırlıdır. Bu, varlığın her gezintisinde bir eylem gerçekleştirmek için kullanılabilir. Örneğin, tüm ilgili varlıkların yüklenmesini zorlamak için:

foreach (var navigationEntry in context.Entry(blog).Navigations)
{
    navigationEntry.Load();
}

Varlığın tüm üyeleriyle çalışma

Normal özellikler ve gezinti özellikleri farklı durum ve davranışa sahiptir. Bu nedenle, yukarıdaki bölümlerde gösterildiği gibi gezintileri ve olmayan gezintileri ayrı ayrı işlemek yaygın bir durumdur. Ancak, bazen varlığın herhangi bir üyesiyle, ister düzenli bir özellik ister gezinme olsun, bir eylem gerçekleştirmek yararlı olabilir. EntityEntry.Member ve EntityEntry.Members bu amaçla sağlanır. Örneğin:

foreach (var memberEntry in context.Entry(blog).Members)
{
    Console.WriteLine(
        $"Member {memberEntry.Metadata.Name} is of type {memberEntry.Metadata.ClrType.ShortDisplayName()} and has value {memberEntry.CurrentValue}");
}

Bu kodun örnekten bir blogda çalıştırılması aşağıdaki çıkışı oluşturur:

Member Id is of type int and has value 1
Member Name is of type string and has value .NET Blog
Member Posts is of type IList<Post> and has value System.Collections.Generic.List`1[Post]

Tavsiye

Değişiklik izleyicisi hata ayıklama görünümü aşağıdaki gibi bilgileri gösterir. Değişiklik izleyicisinin tamamı için hata ayıklama görünümü, izlenen her varlığın bireysel EntityEntry.DebugView öğesinden oluşturulur.

Bul ve BulAsync

DbContext.Find, DbContext.FindAsync, DbSet<TEntity>.Findve DbSet<TEntity>.FindAsync birincil anahtarı bilindiğinde tek bir varlığın verimli bir şekilde aranma amacıyla tasarlanmıştır. Find işlemi, öncelikle varlığın zaten takip edilip edilmediğini kontrol eder ve eğer takip ediliyorsa varlığı anında döndürür. Veritabanı sorgusu yalnızca varlık yerel olarak izlenmiyorsa yapılır. Örneğin, aynı varlık için Bul'u iki kez çağıran bu kodu göz önünde bulundurun:

using var context = new BlogsContext();

Console.WriteLine("First call to Find...");
var blog1 = await context.Blogs.FindAsync(1);

Console.WriteLine($"...found blog {blog1.Name}");

Console.WriteLine();
Console.WriteLine("Second call to Find...");
var blog2 = await context.Blogs.FindAsync(1);
Debug.Assert(blog1 == blog2);

Console.WriteLine("...returned the same instance without executing a query.");

SQLite kullanılırken bu kodun çıkışı (EF Core günlüğü dahil) şöyledir:

First call to Find...
info: 12/29/2020 07:45:53.682 RelationalEventId.CommandExecuted[20101] (Microsoft.EntityFrameworkCore.Database.Command)
      Executed DbCommand (1ms) [Parameters=[@__p_0='1' (DbType = String)], CommandType='Text', CommandTimeout='30']
      SELECT "b"."Id", "b"."Name"
      FROM "Blogs" AS "b"
      WHERE "b"."Id" = @__p_0
      LIMIT 1
...found blog .NET Blog

Second call to Find...
...returned the same instance without executing a query.

İlk çağrının varlığı yerel olarak bulmadığını ve bu nedenle bir veritabanı sorgusu yürüttüğüne dikkat edin. Buna karşılık, ikinci çağrı zaten izlendiğinden veritabanını sorgulamadan aynı örneği döndürür.

Verilen anahtara sahip bir varlık yerel olarak izlenmiyorsa ve veritabanında yoksa Find null döndürür.

Bileşik anahtarlar

Arama, bileşik anahtarlarla da kullanılabilir. Örneğin, sipariş kimliği ve ürün kimliğinden oluşan bileşik anahtara sahip bir varlığı göz önünde bulundurun OrderLine :

public class OrderLine
{
    public int OrderId { get; set; }
    public int ProductId { get; set; }

    //...
}

Bileşik anahtar, anahtar parçalarını DbContext.OnModelCreating tanımlamak için içinde yapılandırılmalıdır. Örneğin:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder
        .Entity<OrderLine>()
        .HasKey(e => new { e.OrderId, e.ProductId });
}

Anahtarın OrderId ilk bölümü ve ProductId anahtarın ikinci bölümü olduğuna dikkat edin. Bu sıra, anahtar değerleri Bul'a geçirildiğinde kullanılmalıdır. Örneğin:

var orderline = await context.OrderLines.FindAsync(orderId, productId);

İzlenen tüm varlıklara erişmek için ChangeTracker.Entrys kullanma

Şu ana kadar tek seferde yalnızca bir taneye EntityEntry erişebildik. ChangeTracker.Entries() DbContext tarafından izlenen her varlık için bir EntityEntry döndürür. Örneğin:

using var context = new BlogsContext();
var blogs = await context.Blogs.Include(e => e.Posts).ToListAsync();

foreach (var entityEntry in context.ChangeTracker.Entries())
{
    Console.WriteLine($"Found {entityEntry.Metadata.Name} entity with ID {entityEntry.Property("Id").CurrentValue}");
}

Bu kod aşağıdaki çıkışı oluşturur:

Found Blog entity with ID 1
Found Post entity with ID 1
Found Post entity with ID 2

Hem bloglar hem de gönderiler için girdilerin döndürüldüğünü fark edin. Bunun yerine sonuçlar, genel aşırı yükleme kullanılarak belirli bir varlık türüne ChangeTracker.Entries<TEntity>() filtrelenebilir:

foreach (var entityEntry in context.ChangeTracker.Entries<Post>())
{
    Console.WriteLine(
        $"Found {entityEntry.Metadata.Name} entity with ID {entityEntry.Property(e => e.Id).CurrentValue}");
}

Bu kodun çıktısı yalnızca gönderilerin döndürüldüğünü gösterir:

Found Post entity with ID 1
Found Post entity with ID 2

Ayrıca, genel aşırı yüklemenin kullanılması genel EntityEntry<TEntity> örnekleri döndürür. Bu, bu örnekte Id özelliğine akıcı bir şekilde erişimi sağlayan şeydir.

Filtreleme için kullanılan genel türün eşlenmiş bir varlık türü olması gerekmez; bunun yerine eşlenmemiş bir temel tür veya arabirim kullanılabilir. Örneğin, modeldeki tüm varlık türleri anahtar özelliklerini tanımlayan bir arabirim uyguluyorsa:

public interface IEntityWithKey
{
    int Id { get; set; }
}

Daha sonra bu arabirim, izlenen herhangi bir varlığın anahtarıyla kesin olarak türlenmiş bir şekilde çalışmak için kullanılabilir. Örneğin:

foreach (var entityEntry in context.ChangeTracker.Entries<IEntityWithKey>())
{
    Console.WriteLine(
        $"Found {entityEntry.Metadata.Name} entity with ID {entityEntry.Property(e => e.Id).CurrentValue}");
}

İzlenen varlıkları sorgulamak için DbSet.Local kullanma

EF Core sorguları her zaman veritabanında yürütülür ve yalnızca veritabanına kaydedilmiş varlıkları döndürür. DbSet<TEntity>.Local yerel, izlenen varlıklar için DbContext'i sorgulamak için bir mekanizma sağlar.

DbSet.Local İzlenen varlıkları sorgulamak için kullanıldığından, varlıkları DbContext'e yüklemek ve ardından bu yüklü varlıklarla çalışmak normaldir. Bu özellikle veri bağlama için geçerlidir, ancak diğer durumlarda da yararlı olabilir. Örneğin, aşağıdaki kodda veritabanı ilk olarak tüm bloglar ve gönderiler için sorgulanır. Load Uzantı yöntemi, doğrudan uygulamaya döndürülmeden bağlam tarafından izlenen sonuçlarla bu sorguyu yürütmek için kullanılır. (ToList veya benzerini kullanmak aynı etkiye sahiptir, ancak burada gerekli olmayan döndürülen listeyi oluşturma yüküyle beraber gelir.) Örnek daha sonra DbSet.Local kullanarak yerel olarak izlenen varlıklara erişir.

using var context = new BlogsContext();

await context.Blogs.Include(e => e.Posts).LoadAsync();

foreach (var blog in context.Blogs.Local)
{
    Console.WriteLine($"Blog: {blog.Name}");
}

foreach (var post in context.Posts.Local)
{
    Console.WriteLine($"Post: {post.Title}");
}

ChangeTracker.Entries()'ın aksine, DbSet.Local doğrudan varlık örneklerini döndürdüğüne dikkat edin. Bir EntityEntry elbette, döndürülen varlık için her zaman DbContext.Entry çağrılarak elde edilebilir.

Yerel görünüm

DbSet<TEntity>.Local, bu varlıkların mevcut EntityState durumunu yansıtan, yerel olarak izlenen varlıkların bir görünümünü döndürür. Bu, özellikle şu anlama gelir:

  • Added varlıklar dahil edilir. Varlıklar henüz veritabanında olmadığından ve bu nedenle veritabanı sorgusu tarafından hiçbir zaman döndürülmediğinden, Added normal EF Core sorguları için bu durumun geçerli olmadığını unutmayın.
  • Deleted varlıklar hariç tutulur. Varlıklar veritabanında hala var olduğundan Deleted ve veritabanı sorguları tarafından döndürüldiğinden , normal EF Core sorguları için bu durumun yine böyle olmadığını unutmayın.

Tüm bunlar, DbSet.Local varlıkların dahil olduğu ve Added varlıkların dışlandığı varlık grafiğinin Deleted geçerli kavramsal durumunu yansıtan veriler üzerinde bir görünüm olduğu anlamına gelir. Bu, SaveChanges çağrıldıktan sonra beklenen veritabanı durumuyla eşleşir.

Bu genellikle veri bağlama için ideal bir görünümdür, çünkü uygulama tarafından yapılan değişikliklere göre verileri kullanıcıya anladığı şekilde sunar.

Aşağıdaki kod, bir gönderiyi olarak Deleted işaretleyip yeni bir gönderi Addedekleyerek bunu gösterir:

using var context = new BlogsContext();

var posts = await context.Posts.Include(e => e.Blog).ToListAsync();

Console.WriteLine("Local view after loading posts:");

foreach (var post in context.Posts.Local)
{
    Console.WriteLine($"  Post: {post.Title}");
}

context.Remove(posts[1]);

context.Add(
    new Post
    {
        Title = "What’s next for System.Text.Json?",
        Content = ".NET 5.0 was released recently and has come with many...",
        Blog = posts[0].Blog
    });

Console.WriteLine("Local view after adding and deleting posts:");

foreach (var post in context.Posts.Local)
{
    Console.WriteLine($"  Post: {post.Title}");
}

Bu kodun çıktısı şu şekildedir:

Local view after loading posts:
  Post: Announcing the Release of EF Core 5.0
  Post: Announcing F# 5
  Post: Announcing .NET 5.0
Local view after adding and deleting posts:
  Post: What’s next for System.Text.Json?
  Post: Announcing the Release of EF Core 5.0
  Post: Announcing .NET 5.0

Silinen gönderinin yerel görünümden kaldırıldığına ve eklenen gönderinin eklendiğine dikkat edin.

Varlık eklemek ve kaldırmak için Yerel'i kullanma

DbSet<TEntity>.Local, bir LocalView<TEntity> örneği döndürür. Bu, varlıklar eklendiğinde ve koleksiyondan kaldırıldığında bildirimler oluşturan ve bunlara yanıt veren bir uygulamasıdır ICollection<T> . (Bu, ile aynı kavramdır ObservableCollection<T>, ancak bağımsız bir koleksiyon olarak değil, mevcut EF Core değişiklik izleme girdileri üzerinde bir projeksiyon olarak uygulanır.)

Yerel görünümün bildirimleri DbContext değişiklik izlemesine bağlanarak yerel görünümün DbContext ile eşitlenmiş durumda kalmasını sağlar. Özellikle:

  • DbSet.Local içine yeni bir varlık eklemek, genellikle Added durumunda DbContext tarafından izlenmesine neden olur. (Varlık zaten oluşturulmuş bir anahtar değerine sahipse, Unchanged olarak izlenir.)
  • Bir varlığın DbSet.Local'den kaldırılması, onun Deleted olarak işaretlenmesine neden olur.
  • DbContext tarafından izlenen bir varlık, DbSet.Local koleksiyonunda otomatik olarak görünür. Örneğin, daha fazla varlığın otomatik olarak getirilmesi için bir sorgunun yürütülmesi yerel görünümün güncelleştirilmiş olmasına neden olur.
  • olarak Deleted işaretlenmiş bir varlık, yerel koleksiyondan otomatik olarak kaldırılır.

Bu, yerel görünümün izlenen varlıkları yalnızca koleksiyona ekleyip kaldırarak işlemek için kullanılabileceğini gösterir. Örneğin, yerel koleksiyona gönderi eklemek ve kaldırmak için önceki örnek kodu değiştirelim:

using var context = new BlogsContext();

var posts = await context.Posts.Include(e => e.Blog).ToListAsync();

Console.WriteLine("Local view after loading posts:");

foreach (var post in context.Posts.Local)
{
    Console.WriteLine($"  Post: {post.Title}");
}

context.Posts.Local.Remove(posts[1]);

context.Posts.Local.Add(
    new Post
    {
        Title = "What’s next for System.Text.Json?",
        Content = ".NET 5.0 was released recently and has come with many...",
        Blog = posts[0].Blog
    });

Console.WriteLine("Local view after adding and deleting posts:");

foreach (var post in context.Posts.Local)
{
    Console.WriteLine($"  Post: {post.Title}");
}

Yerel görünümde yapılan değişiklikler DbContext ile eşitlendiği için çıkış önceki örnekten farklı kalır.

Windows Forms veya WPF veri bağlaması için yerel görünümü kullanma

DbSet<TEntity>.Local EF Core varlıklarına veri bağlamanın temelini oluşturur. Ancak, hem Windows Forms hem de WPF, beklediğiniz bildirim koleksiyonunun belirli türüyle kullanıldığında en iyi şekilde çalışır. Yerel görünüm şu koleksiyon türlerinin oluşturulmasını destekler:

Örneğin:

ObservableCollection<Post> observableCollection = context.Posts.Local.ToObservableCollection();
BindingList<Post> bindingList = context.Posts.Local.ToBindingList();

EF Core ile WPF veri bağlama hakkında daha fazla bilgi için WPF ile Çalışmaya Başlama'ya göz atın ve EF Core ile Windows Forms veri bağlama hakkında daha fazla bilgi için Windows Forms ile Çalışmaya Başlama'ya bakın.

Tavsiye

Belirli bir DbSet örneğinin yerel görünümü ilk erişildiğinde ve sonra önbelleğe alındığında gevşek bir şekilde oluşturulur. LocalView oluşturma işlemi hızlıdır ve önemli bellek kullanmaz. Ancak, çok sayıda varlık için yavaş olabilecek DetectChanges'i çağırır. ToObservableCollection ve ToBindingList tarafından oluşturulan koleksiyonlar da tembel bir şekilde oluşturulur ve ardından önbelleğe alınır. Bu yöntemlerin her ikisi de yavaş olabilecek ve binlerce varlık söz konusu olduğunda çok fazla bellek kullanabilen yeni koleksiyonlar oluşturur.