Lokale DatenLocal Data

Wenn Sie eine LINQ-Abfrage direkt für ein dbset ausführen, wird immer eine Abfrage an die Datenbank gesendet. Sie können jedoch auf die Daten zugreifen, die derzeit im Arbeitsspeicher vorhanden sind, indem Sie die dbset. Local-Eigenschaft verwenden.Running a LINQ query directly against a DbSet will always send a query to the database, but you can access the data that is currently in-memory using the DbSet.Local property. Sie können auch auf die zusätzlichen Informationen zugreifen, die EF über die Entitäten nachverfolgt, indem Sie die Methoden dbcontext. Entry und dbcontext. ChangeTracker. Entries verwenden.You can also access the extra information EF is tracking about your entities using the DbContext.Entry and DbContext.ChangeTracker.Entries methods. Die in diesem Thema dargestellten Techniken gelten jeweils für Modelle, die mit Code First und dem EF-Designer erstellt wurden.The techniques shown in this topic apply equally to models created with Code First and the EF Designer.

Verwenden von local, um lokale Daten zu untersuchenUsing Local to look at local data

Die Local-Eigenschaft von dbset bietet einfachen Zugriff auf die Entitäten der Menge, die zurzeit vom Kontext nachverfolgt werden und nicht als gelöscht markiert wurden.The Local property of DbSet provides simple access to the entities of the set that are currently being tracked by the context and have not been marked as Deleted. Der Zugriff auf die lokale Eigenschaft bewirkt nie, dass eine Abfrage an die Datenbank gesendet wird.Accessing the Local property never causes a query to be sent to the database. Dies bedeutet, dass Sie normalerweise verwendet wird, wenn bereits eine Abfrage durchgeführt wurde.This means that it is usually used after a query has already been performed. Die Load-Erweiterungsmethode kann verwendet werden, um eine Abfrage auszuführen, sodass der Kontext die Ergebnisse nachverfolgt.The Load extension method can be used to execute a query so that the context tracks the results. Beispiel:For example:

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);
    }
}

Wenn wir zwei Blogs in der Datenbank haben: "ADO.net Blog" with a BlogId of 1 und "The Visual Studio Blog" with a BlogId of 2-Wir könnten die folgende Ausgabe erwarten:If we had two blogs in the database - 'ADO.NET Blog' with a BlogId of 1 and 'The Visual Studio Blog' with a BlogId of 2 - we could expect the following output:

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

Dies veranschaulicht drei Punkte:This illustrates three points:

  • Der neue Blog "Mein neuer Blog" ist in der lokalen Sammlung enthalten, obwohl er noch nicht in der Datenbank gespeichert wurde.The new blog 'My New Blog' is included in the Local collection even though it has not yet been saved to the database. In diesem Blog ist der Primärschlüssel 0 (null), da die Datenbank noch keinen echten Schlüssel für die Entität generiert hat.This blog has a primary key of zero because the database has not yet generated a real key for the entity.
  • Der ADO.net-Blog ist nicht in der lokalen Auflistung enthalten, obwohl er noch vom Kontext nachverfolgt wird.The 'ADO.NET Blog' is not included in the local collection even though it is still being tracked by the context. Der Grund hierfür ist, dass wir ihn aus dem dbset entfernt haben und ihn als gelöscht markieren.This is because we removed it from the DbSet thereby marking it as deleted.
  • Wenn dbset zum Ausführen einer Abfrage verwendet wird, ist der zum Löschen markierte Blog (ADO.net-Blog) in den Ergebnissen enthalten, und der neue Blog (mein neuer Blog), der noch nicht in der Datenbank gespeichert wurde, ist nicht in den Ergebnissen enthalten.When DbSet is used to perform a query the blog marked for deletion (ADO.NET Blog) is included in the results and the new blog (My New Blog) that has not yet been saved to the database is not included in the results. Dies liegt daran, dass dbset eine Abfrage für die Datenbank ausführt und die zurückgegebenen Ergebnisse immer den Inhalt der Datenbank widerspiegeln.This is because DbSet is performing a query against the database and the results returned always reflect what is in the database.

Verwenden von local zum Hinzufügen und Entfernen von Entitäten aus dem KontextUsing Local to add and remove entities from the context

Die Local-Eigenschaft in dbset gibt eine ObservableCollection mit gehockten Ereignissen zurück, sodass Sie mit dem Inhalt des Kontexts synchron bleibt.The Local property on DbSet returns an ObservableCollection with events hooked up such that it stays in sync with the contents of the context. Dies bedeutet, dass Entitäten entweder der lokalen Auflistung oder dem dbset hinzugefügt oder daraus entfernt werden können.This means that entities can be added or removed from either the Local collection or the DbSet. Dies bedeutet auch, dass Abfragen, die neue Entitäten in den Kontext bringen, dazu führen, dass die lokale Sammlung mit diesen Entitäten aktualisiert wird.It also means that queries that bring new entities into the context will result in the Local collection being updated with those entities. Beispiel:For example:

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);
    }
}

Wenn einige Beiträge mit "Entity-Framework" und "ASP.net" gekennzeichnet sind, sieht die Ausgabe in etwa wie folgt aus:Assuming we had a few posts tagged with 'entity-framework' and 'asp.net' the output may look something like this:

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

Dies veranschaulicht drei Punkte:This illustrates three points:

  • Der neue Beitrag ' What es New in EF ', der der lokalen Auflistung hinzugefügt wurde, wird vom Kontext im hinzugefügten Zustand nachverfolgt.The new post 'What's New in EF' that was added to the Local collection becomes tracked by the context in the Added state. Sie wird daher in die Datenbank eingefügt, wenn SaveChanges aufgerufen wird.It will therefore be inserted into the database when SaveChanges is called.
  • Der Beitrag, der aus der lokalen Sammlung entfernt wurde (EF-Anfänger Handbuch) ist jetzt im Kontext als gelöscht gekennzeichnet.The post that was removed from the Local collection (EF Beginners Guide) is now marked as deleted in the context. Daher wird Sie aus der Datenbank gelöscht, wenn SaveChanges aufgerufen wird.It will therefore be deleted from the database when SaveChanges is called.
  • Der zusätzliche Post (ASP.net Beginners Guide), der mit der zweiten Abfrage in den Kontext geladen wird, wird der lokalen Auflistung automatisch hinzugefügt.The additional post (ASP.NET Beginners Guide) loaded into the context with the second query is automatically added to the Local collection.

Eine letzte Anmerkung zu Local ist, dass es sich bei einer ObservableCollection-Leistung nicht hervorragend für eine große Anzahl von Entitäten eignet.One final thing to note about Local is that because it is an ObservableCollection performance is not great for large numbers of entities. Wenn Sie also Tausende von Entitäten in ihrem Kontext verwenden, ist es möglicherweise nicht empfehlenswert, lokale zu verwenden.Therefore if you are dealing with thousands of entities in your context it may not be advisable to use Local.

Verwenden von Local für die WPF-DatenbindungUsing Local for WPF data binding

Die lokale Eigenschaft in dbset kann direkt für die Datenbindung in einer WPF-Anwendung verwendet werden, da es sich um eine Instanz von ObservableCollection handelt.The Local property on DbSet can be used directly for data binding in a WPF application because it is an instance of ObservableCollection. Wie in den vorherigen Abschnitten beschrieben, bedeutet dies, dass Sie automatisch mit dem Inhalt des Kontexts synchronisiert wird und der Inhalt des Kontexts automatisch synchron bleibt.As described in the previous sections this means that it will automatically stay in sync with the contents of the context and the contents of the context will automatically stay in sync with it. Beachten Sie, dass Sie die lokale Sammlung mit Daten füllen müssen, damit Sie an eine Bindung gebunden werden, da local nie eine Datenbankabfrage verursacht.Note that you do need to pre-populate the Local collection with data for there to be anything to bind to since Local never causes a database query.

Dies ist kein geeigneter Ort für ein vollständiges WPF-Daten Bindungs Beispiel, aber die wichtigsten Elemente sind:This is not an appropriate place for a full WPF data binding sample but the key elements are:

  • Einrichten einer Bindungs QuelleSetup a binding source
  • Binden Sie es an die lokale Eigenschaft ihrer Gruppe.Bind it to the Local property of your set
  • Füllen Sie local mithilfe einer Abfrage an die Datenbank auf.Populate Local using a query to the database.

WPF-Bindung an Navigations EigenschaftenWPF binding to navigation properties

Wenn Sie die Master/Detail-Datenbindung durchgeführt haben, möchten Sie möglicherweise die Detailansicht an eine Navigations Eigenschaft einer ihrer Entitäten binden.If you are doing master/detail data binding you may want to bind the detail view to a navigation property of one of your entities. Eine einfache Möglichkeit, dies zu tun, ist die Verwendung einer ObservableCollection für die Navigations Eigenschaft.An easy way to make this work is to use an ObservableCollection for the navigation property. Beispiel:For example:

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; }
    }
}

Verwenden von local zum Bereinigen von Entitäten in SaveChangesUsing Local to clean up entities in SaveChanges

In den meisten Fällen werden Entitäten, die aus einer Navigations Eigenschaft entfernt werden, im Kontext nicht automatisch als gelöscht markiert.In most cases entities removed from a navigation property will not be automatically marked as deleted in the context. Wenn Sie z. b. ein Post-Objekt aus der Blog. Posts-Sammlung entfernen, wird dieser Beitrag nicht automatisch gelöscht, wenn SaveChanges aufgerufen wird.For example, if you remove a Post object from the Blog.Posts collection then that post will not be automatically deleted when SaveChanges is called. Wenn Sie den Löschvorgang benötigen, müssen Sie möglicherweise diese verbleibenden Entitäten suchen und als gelöscht markieren, bevor Sie SaveChanges oder als Teil einer überschriebenen SaveChanges aufrufen.If you need it to be deleted then you may need to find these dangling entities and mark them as deleted before calling SaveChanges or as part of an overridden SaveChanges. Beispiel:For example:

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

    return base.SaveChanges();
}

Der obige Code verwendet die lokale Auflistung, um nach allen Beiträgen zu suchen, und kennzeichnet alle, die keinen Blog Verweis als gelöscht haben.The code above uses the Local collection to find all posts and marks any that do not have a blog reference as deleted. Der Auflistungs aufrufsvorgang ist erforderlich, da die Auflistung andernfalls durch den remove-Befehl geändert wird, während diese aufgelistet wird.The ToList call is required because otherwise the collection will be modified by the Remove call while it is being enumerated. In den meisten anderen Situationen können Sie die lokale Eigenschaft direkt Abfragen, ohne zuerst zuerst "-List" zu verwenden.In most other situations you can query directly against the Local property without using ToList first.

Verwenden von "local" und "ToBindingList" für Windows Forms DatenbindungUsing Local and ToBindingList for Windows Forms data binding

Windows Forms unterstützt die Datenbindung mit vollständiger Genauigkeit nicht direkt mithilfe von ObservableCollection.Windows Forms does not support full fidelity data binding using ObservableCollection directly. Sie können jedoch weiterhin die lokale dbset-Eigenschaft für die Datenbindung verwenden, um alle Vorteile zu erhalten, die in den vorherigen Abschnitten beschrieben wurden.However, you can still use the DbSet Local property for data binding to get all the benefits described in the previous sections. Dies wird durch die "debindinglist"-Erweiterungsmethode erreicht, die eine IBindingList -Implementierung erstellt, die von der lokalen ObservableCollection unterstützt wird.This is achieved through the ToBindingList extension method which creates an IBindingList implementation backed by the Local ObservableCollection.

Dies ist kein geeigneter Ort für ein vollständiges Windows Forms Daten Bindungs Beispiel, aber die wichtigsten Elemente sind:This is not an appropriate place for a full Windows Forms data binding sample but the key elements are:

  • Einrichten einer Objekt Bindungs QuelleSetup an object binding source
  • Binden Sie es an die lokale Eigenschaft ihrer Gruppe, indem Sie local. debindinglist () verwenden.Bind it to the Local property of your set using Local.ToBindingList()
  • Lokales Auffüllen mithilfe einer Abfrage an die DatenbankPopulate Local using a query to the database

Ausführliche Informationen zu nach verfolgten EntitätenGetting detailed information about tracked entities

Viele der Beispiele in dieser Reihe verwenden die Entry-Methode, um eine dbentityentry-Instanz für eine Entität zurückzugeben.Many of the examples in this series use the Entry method to return a DbEntityEntry instance for an entity. Dieses Einstiegs Objekt fungiert dann als Ausgangspunkt für das Sammeln von Informationen über die Entität, z. b. den aktuellen Status, sowie für das Ausführen von Vorgängen für die Entität, z. b. das explizite Laden einer verknüpften EntitätThis entry object then acts as the starting point for gathering information about the entity such as its current state, as well as for performing operations on the entity such as explicitly loading a related entity.

Die Entries-Methoden geben dbentityentry-Objekte für viele oder alle Entitäten zurück, die vom Kontext nachverfolgt werden.The Entries methods return DbEntityEntry objects for many or all entities being tracked by the context. Dies ermöglicht es Ihnen, Informationen zu sammeln oder Vorgänge für viele Entitäten statt nur für einen einzelnen Eintrag auszuführen.This allows you to gather information or perform operations on many entities rather than just a single entry. Beispiel:For example:

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);
    }
}

Sie werden feststellen, dass wir eine Author-und Reader-Klasse in das Beispiel einführen. beide Klassen implementieren die IPerson-Schnittstelle.You'll notice we are introducing a Author and Reader class into the example - both of these classes implement the IPerson interface.

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; }
}

Angenommen, wir haben die folgenden Daten in der Datenbank:Let's assume we have the following data in the database:

Blog mit BlogId = 1 und Name = "ADO.net Blog"Blog with BlogId = 1 and Name = 'ADO.NET Blog'
Blog mit BlogId = 2 und Name = "der Visual Studio-Blog"Blog with BlogId = 2 and Name = 'The Visual Studio Blog'
Blog mit BlogId = 3 und Name = ".NET Framework Blog"Blog with BlogId = 3 and Name = '.NET Framework Blog'
Autor mit AutorID = 1 und Name = ' Joe Bloggs 'Author with AuthorId = 1 and Name = 'Joe Bloggs'
Reader mit readerid = 1 und Name = ' John Doe 'Reader with ReaderId = 1 and Name = 'John Doe'

Die Ausgabe der Ausführung des Codes lautet wie folgt:The output from running the code would be:

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

In diesen Beispielen werden mehrere Punkte veranschaulicht:These examples illustrate several points:

  • Die Entries-Methoden geben Einträge für Entitäten in allen Zuständen zurück, einschließlich des gelöschten.The Entries methods return entries for entities in all states, including Deleted. Vergleichen Sie dies mit Local, wodurch gelöschte Entitäten ausgeschlossen werden.Compare this to Local which excludes Deleted entities.
  • Einträge für alle Entitäts Typen werden zurückgegeben, wenn die nicht generische Entries-Methode verwendet wird.Entries for all entity types are returned when the non-generic Entries method is used. Wenn die generische Entries-Methode verwendet wird, werden Einträge nur für Entitäten zurückgegeben, die Instanzen des generischen Typs sind.When the generic entries method is used entries are only returned for entities that are instances of the generic type. Dies wurde oben verwendet, um Einträge für alle Blogs zu erhalten.This was used above to get entries for all blogs. Es wurde auch verwendet, um Einträge für alle Entitäten zu erhalten, die IPerson implementieren.It was also used to get entries for all entities that implement IPerson. Dies zeigt, dass es sich bei dem generischen Typ nicht um einen tatsächlichen Entitätstyp handeln muss.This demonstrates that the generic type does not have to be an actual entity type.
  • LINQ to Objects können verwendet werden, um die zurückgegebenen Ergebnisse zu filtern.LINQ to Objects can be used to filter the results returned. Dies wurde oben verwendet, um Entitäten eines beliebigen Typs zu suchen, solange Sie geändert werden.This was used above to find entities of any type as long as they are modified.

Beachten Sie, dass die dbentityentry-Instanzen immer eine Entität ungleich NULL enthalten.Note that DbEntityEntry instances always contain a non-null Entity. Beziehungs Einträge und Stub-Einträge werden nicht als dbentityentry-Instanzen dargestellt, sodass es nicht erforderlich ist, diese zu filtern.Relationship entries and stub entries are not represented as DbEntityEntry instances so there is no need to filter for these.