Aracılığıyla paylaş


Yerel Veriler

Doğrudan bir DbSet üzerinde LINQ sorgusu çalıştırmak veritabanına her zaman bir sorgu gönderir, ancak dbSet.Local özelliğini kullanarak şu anda bellekte olan verilere erişebilirsiniz. DbContext.Entry ve DbContext.ChangeTracker.Entries yöntemlerini kullanarak EF'nin varlıklarınız hakkında izlediği ek bilgilere de erişebilirsiniz. Bu konu başlığında gösterilen teknikler, gerek Code First gerekse EF Designer ile oluşturulan modellere için geçerlidir.

Yerel verilere bakmak için Yerel'i kullanma

DbSet'in Local özelliği, şu anda bağlam tarafından izlenmekte olan ve Silinmiş olarak işaretlenmemiş küme varlıklarına basit erişim sağlar. Local özelliğine erişmek hiçbir zaman veritabanına bir sorgu gönderilmesine neden olmaz. Bu, genellikle bir sorgu zaten gerçekleştirildikten sonra kullanıldığı anlamına gelir. Load uzantısı yöntemi, bağlamın sonuçları izlemesi için bir sorgu yürütmek için kullanılabilir. Örnek:

using (var context = new BloggingContext())
{
    // Load all blogs from the database into the context
    context.Blogs.Load();

    // Add a new blog to the context
    context.Blogs.Add(new Blog { Name = "My New Blog" });

    // Mark one of the existing blogs as Deleted
    context.Blogs.Remove(context.Blogs.Find(1));

    // Loop over the blogs in the context.
    Console.WriteLine("In Local: ");
    foreach (var blog in context.Blogs.Local)
    {
        Console.WriteLine(
            "Found {0}: {1} with state {2}",
            blog.BlogId,  
            blog.Name,
            context.Entry(blog).State);
    }

    // Perform a query against the database.
    Console.WriteLine("\nIn DbSet query: ");
    foreach (var blog in context.Blogs)
    {
        Console.WriteLine(
            "Found {0}: {1} with state {2}",
            blog.BlogId,  
            blog.Name,
            context.Entry(blog).State);
    }
}

Veritabanında 1 Blog Kimliğine sahip 'ADO.NET Blog' ve BlogId değeri 2 olan 'Visual Studio Blogu' olmak üzere iki blogumuz olsaydı aşağıdaki çıkışı bekleyebilirsiniz:

In Local:
Found 0: My New Blog with state Added
Found 2: The Visual Studio Blog with state Unchanged

In DbSet query:
Found 1: ADO.NET Blog with state Deleted
Found 2: The Visual Studio Blog with state Unchanged

Bu üç noktayı gösterir:

  • Yeni blog 'Yeni Blogum' henüz veritabanına kaydedilmemiş olsa bile Yerel koleksiyona eklenir. Veritabanı henüz varlık için gerçek bir anahtar oluşturmadığından bu blogun birincil anahtarı sıfırdır.
  • 'ADO.NET Blogu', bağlam tarafından hala izleniyor olsa bile yerel koleksiyona dahil edilmez. Bunun nedeni DbSet'ten kaldırmamız ve böylece silinmiş olarak işaretlememizdir.
  • DbSet bir sorgu gerçekleştirmek için kullanıldığında, silinmek üzere işaretlenmiş blog (ADO.NET Blog) sonuçlara eklenir ve henüz veritabanına kaydedilmemiş olan yeni blog (Yeni Blogum) sonuçlara dahil değildir. Bunun nedeni DbSet'in veritabanında bir sorgu gerçekleştirmesi ve döndürülen sonuçların her zaman veritabanındakileri yansıtmasıdır.

Yerel'i kullanarak bağlama varlık ekleme ve kaldırma

DbSet'teki Local özelliği, bağlama bağlı olaylarla observableCollection döndürür, böylece bağlamın içeriğiyle eşitlenmiş olarak kalır. Bu, varlıkların Yerel koleksiyon veya DbSet'ten eklenebileceği veya kaldırılabildiği anlamına gelir. Bu, bağlama yeni varlıklar getiren sorguların Yerel koleksiyonun bu varlıklarla güncelleştirilmesiyle sonuçlanacağı anlamına da gelir. Örnek:

using (var context = new BloggingContext())
{
    // Load some posts from the database into the context
    context.Posts.Where(p => p.Tags.Contains("entity-framework")).Load();  

    // Get the local collection and make some changes to it
    var localPosts = context.Posts.Local;
    localPosts.Add(new Post { Name = "What's New in EF" });
    localPosts.Remove(context.Posts.Find(1));  

    // Loop over the posts in the context.
    Console.WriteLine("In Local after entity-framework query: ");
    foreach (var post in context.Posts.Local)
    {
        Console.WriteLine(
            "Found {0}: {1} with state {2}",
            post.Id,  
            post.Title,
            context.Entry(post).State);
    }

    var post1 = context.Posts.Find(1);
    Console.WriteLine(
        "State of post 1: {0} is {1}",
        post1.Name,  
        context.Entry(post1).State);  

    // Query some more posts from the database
    context.Posts.Where(p => p.Tags.Contains("asp.net")).Load();  

    // Loop over the posts in the context again.
    Console.WriteLine("\nIn Local after asp.net query: ");
    foreach (var post in context.Posts.Local)
    {
        Console.WriteLine(
            "Found {0}: {1} with state {2}",
            post.Id,  
            post.Title,
            context.Entry(post).State);
    }
}

'entity-framework' ve 'asp.net' etiketli birkaç gönderimiz olduğunu varsayarsak çıktı aşağıdaki gibi görünebilir:

In Local after entity-framework query:
Found 3: EF Designer Basics with state Unchanged
Found 5: EF Code First Basics with state Unchanged
Found 0: What's New in EF with state Added
State of post 1: EF Beginners Guide is Deleted

In Local after asp.net query:
Found 3: EF Designer Basics with state Unchanged
Found 5: EF Code First Basics with state Unchanged
Found 0: What's New in EF with state Added
Found 4: ASP.NET Beginners Guide with state Unchanged

Bu üç noktayı gösterir:

  • Yerel koleksiyona eklenen yeni 'EF'teki Yenilikler' gönderisi, Eklendi durumundaki bağlam tarafından izlenir. Bu nedenle SaveChanges çağrıldığında veritabanına eklenir.
  • Yerel koleksiyondan kaldırılan gönderi (EF Başlangıç Kılavuzu) artık bağlamda silinmiş olarak işaretlenir. Bu nedenle SaveChanges çağrıldığında veritabanından silinir.
  • İkinci sorguyla bağlama yüklenen ek gönderi (ASP.NET Başlangıç Kılavuzu) otomatik olarak Yerel koleksiyona eklenir.

Yerel hakkında dikkate alınmaması gereken son noktalardan biri, ObservableCollection performansının çok sayıda varlık için harika olmamasıdır. Bu nedenle, bağlamınızdaki binlerce varlıkla ilgileniyorsanız Yerel'i kullanmanız önerilmez.

WPF veri bağlaması için Yerel'i kullanma

ObservableCollection örneği olduğundan DbSet'teki Local özelliği bir WPF uygulamasında veri bağlama için doğrudan kullanılabilir. Önceki bölümlerde açıklandığı gibi bu, bağlamın içeriğiyle otomatik olarak eşitlenmiş olarak kalacağı ve bağlamın içeriğinin otomatik olarak onunla eşitlenmiş olarak kalacağı anlamına gelir. Local hiçbir zaman veritabanı sorgusuna neden olmadığından bağlanılacak herhangi bir şey olması için Local koleksiyonunu verilerle önceden doldurmanız gerektiğini unutmayın.

Burası tam WPF veri bağlama örneği için uygun bir yer değildir, ancak temel öğeler şunlardır:

  • Bağlama kaynağı ayarlama
  • Kümenizin Local özelliğine bağlama
  • Veritabanına bir sorgu kullanarak Yerel'i doldurun.

Gezinti özelliklerine WPF bağlama

Ana/ayrıntı veri bağlaması yapıyorsanız, ayrıntı görünümünü varlıklarınızdan birinin gezinti özelliğine bağlamak isteyebilirsiniz. Bu işi yapabilmenin kolay bir yolu, gezinti özelliği için ObservableCollection kullanmaktır. Örnek:

public class Blog
{
    private readonly ObservableCollection<Post> _posts =
        new ObservableCollection<Post>();

    public int BlogId { get; set; }
    public string Name { get; set; }

    public virtual ObservableCollection<Post> Posts
    {
        get { return _posts; }
    }
}

SaveChanges'te varlıkları temizlemek için Yerel'i kullanma

Çoğu durumda gezinti özelliğinden kaldırılan varlıklar, bağlamda otomatik olarak silinmiş olarak işaretlenmez. Örneğin, Blog.Posts koleksiyonundan bir Post nesnesini kaldırırsanız, SaveChanges çağrıldığında bu gönderi otomatik olarak silinmez. Silinmesi gerekiyorsa, SaveChanges'i çağırmadan önce veya geçersiz kılınmış Bir SaveChanges'in parçası olarak bu sarkan varlıkları bulmanız ve silinmiş olarak işaretlemeniz gerekebilir. Örnek:

public override int SaveChanges()
{
    foreach (var post in this.Posts.Local.ToList())
    {
        if (post.Blog == null)
        {
            this.Posts.Remove(post);
        }
    }

    return base.SaveChanges();
}

Yukarıdaki kod, tüm gönderileri bulmak için Yerel koleksiyonunu kullanır ve blog başvurusu olmayanları silindi olarak işaretler. ToList çağrısı gereklidir, aksi takdirde koleksiyon numaralandırılırken Remove çağrısı tarafından değiştirilir. Diğer çoğu durumda, önce ToList kullanmadan doğrudan Local özelliğine karşı sorgulayabilirsiniz.

Windows Forms veri bağlaması için Local ve ToBindingList kullanma

Windows Forms, ObservableCollection kullanılarak doğrudan tam uygunluk veri bağlamayı desteklemez. Ancak, önceki bölümlerde açıklanan tüm avantajları elde etmek için veri bağlama için DbSet Local özelliğini kullanmaya devam edebilirsiniz. Bu, Local ObservableCollection tarafından yedeklenen bir IBindingList uygulaması oluşturan ToBindingList uzantısı yöntemiyle elde edilir.

Burası tam bir Windows Forms veri bağlama örneği için uygun bir yer değildir, ancak temel öğeler şunlardır:

  • Nesne bağlama kaynağını ayarlama
  • Local.ToBindingList() kullanarak kümenizin Local özelliğine bağlayın
  • Veritabanına sorgu kullanarak Yerel'i doldurma

İzlenen varlıklar hakkında ayrıntılı bilgi alma

Bu serideki örneklerin çoğu, bir varlık için DbEntityEntry örneği döndürmek için Entry yöntemini kullanır. Bu giriş nesnesi daha sonra varlık hakkında geçerli durumu gibi bilgileri toplamak ve varlık üzerinde açıkça ilgili bir varlığı yükleme gibi işlemler gerçekleştirmek için başlangıç noktası olarak görev yapar.

Entrys yöntemleri, bağlam tarafından izlenen birçok veya tüm varlıklar için DbEntityEntry nesneleri döndürür. Bu, yalnızca tek bir giriş yerine birçok varlıkta bilgi toplamanıza veya işlemler gerçekleştirmenize olanak tanır. Örnek:

using (var context = new BloggingContext())
{
    // Load some entities into the context
    context.Blogs.Load();
    context.Authors.Load();
    context.Readers.Load();

    // Make some changes
    context.Blogs.Find(1).Title = "The New ADO.NET Blog";
    context.Blogs.Remove(context.Blogs.Find(2));
    context.Authors.Add(new Author { Name = "Jane Doe" });
    context.Readers.Find(1).Username = "johndoe1987";

    // Look at the state of all entities in the context
    Console.WriteLine("All tracked entities: ");
    foreach (var entry in context.ChangeTracker.Entries())
    {
        Console.WriteLine(
            "Found entity of type {0} with state {1}",
            ObjectContext.GetObjectType(entry.Entity.GetType()).Name,
            entry.State);
    }

    // Find modified entities of any type
    Console.WriteLine("\nAll modified entities: ");
    foreach (var entry in context.ChangeTracker.Entries()
                              .Where(e => e.State == EntityState.Modified))
    {
        Console.WriteLine(
            "Found entity of type {0} with state {1}",
            ObjectContext.GetObjectType(entry.Entity.GetType()).Name,
            entry.State);
    }

    // Get some information about just the tracked blogs
    Console.WriteLine("\nTracked blogs: ");
    foreach (var entry in context.ChangeTracker.Entries<Blog>())
    {
        Console.WriteLine(
            "Found Blog {0}: {1} with original Name {2}",
            entry.Entity.BlogId,  
            entry.Entity.Name,
            entry.Property(p => p.Name).OriginalValue);
    }

    // Find all people (author or reader)
    Console.WriteLine("\nPeople: ");
    foreach (var entry in context.ChangeTracker.Entries<IPerson>())
    {
        Console.WriteLine("Found Person {0}", entry.Entity.Name);
    }
}

Bu sınıflardan her ikisi de IPerson arabirimini uygulayarak bir Yazar ve Okuyucu sınıfını kullanıma sunduğumuzu fark edeceksiniz.

public class Author : IPerson
{
    public int AuthorId { get; set; }
    public string Name { get; set; }
    public string Biography { get; set; }
}

public class Reader : IPerson
{
    public int ReaderId { get; set; }
    public string Name { get; set; }
    public string Username { get; set; }
}

public interface IPerson
{
    string Name { get; }
}

Veritabanında aşağıdaki verilere sahip olduğumuzu varsayalım:

BlogId = 1 ve Ad = 'ADO.NET Blog' içeren blog
BlogId = 2 ve Ad = 'Visual Studio Blogu' ile blog
BlogId = 3 ve Ad = '.NET Framework Blogu' ile Blog
AuthorId = 1 ve Name = 'Joe Bloggs' içeren yazar
ReaderId = 1 ve Name = 'John Doe' ile Okuyucu

Kodu çalıştırmanın çıkışı şöyle olacaktır:

All tracked entities:
Found entity of type Blog with state Modified
Found entity of type Blog with state Deleted
Found entity of type Blog with state Unchanged
Found entity of type Author with state Unchanged
Found entity of type Author with state Added
Found entity of type Reader with state Modified

All modified entities:
Found entity of type Blog with state Modified
Found entity of type Reader with state Modified

Tracked blogs:
Found Blog 1: The New ADO.NET Blog with original Name ADO.NET Blog
Found Blog 2: The Visual Studio Blog with original Name The Visual Studio Blog
Found Blog 3: .NET Framework Blog with original Name .NET Framework Blog

People:
Found Person John Doe
Found Person Joe Bloggs
Found Person Jane Doe

Bu örneklerde birkaç nokta gösterilmektedir:

  • Entrys yöntemleri, Silinmiş de dahil olmak üzere tüm durumlardaki varlıklar için girdiler döndürür. Bunu, Silinmiş varlıkları dışlayan Yerel ile karşılaştırın.
  • Genel olmayan Entrys yöntemi kullanıldığında tüm varlık türleri için girdiler döndürülür. Genel girişler yöntemi kullanıldığında, girişler yalnızca genel türün örnekleri olan varlıklar için döndürülür. Bu, tüm blogların girdilerini almak için yukarıda kullanılmıştır. Ayrıca IPerson uygulayan tüm varlıkların girdilerini almak için de kullanılmıştır. Bu, genel türün gerçek bir varlık türü olması gerekmediğini gösterir.
  • Döndürülen sonuçları filtrelemek için LINQ to Objects kullanılabilir. Bu, değiştirildiği sürece herhangi bir türün varlıklarını bulmak için yukarıda kullanılmıştır.

DbEntityEntry örneklerinin her zaman null olmayan bir Varlık içerdiğini unutmayın. İlişki girdileri ve saplama girişleri DbEntityEntry örnekleri olarak temsil edilmediğinden, bunlar için filtrelemeye gerek yoktur.