Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
Als u een LINQ-query rechtstreeks uitvoert op basis van een DbSet, wordt altijd een query naar de database verzonden, maar u hebt toegang tot de gegevens die zich momenteel in het geheugen bevinden met behulp van de eigenschap DbSet.Local. U kunt ook toegang krijgen tot de extra informatie die EF bijhoudt over uw entiteiten met behulp van de methoden DbContext.Entry en DbContext.ChangeTracker.Entries. De technieken die in dit onderwerp worden weergegeven, zijn evenzeer van toepassing op modellen die zijn gemaakt met Code First en de EF Designer.
Lokaal gebruiken om lokale gegevens te bekijken
De eigenschap Local van DbSet biedt eenvoudige toegang tot de entiteiten van de set die momenteel worden bijgehouden door de context en zijn niet gemarkeerd als Verwijderd. Als u de eigenschap Lokaal opent, wordt er nooit een query naar de database verzonden. Dit betekent dat deze meestal wordt gebruikt nadat een query al is uitgevoerd. De methode Load Extension kan worden gebruikt om een query uit te voeren, zodat de context de resultaten bijhoudt. Voorbeeld:
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);
}
}
Als we twee blogs in de database hebben : 'ADO.NET Blog' met een BlogId van 1 en 'The Visual Studio Blog' met een BlogId van 2, kunnen we de volgende uitvoer verwachten:
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
Dit illustreert drie punten:
- De nieuwe blog 'Mijn nieuwe blog' is opgenomen in de lokale verzameling, ook al is deze nog niet opgeslagen in de database. Dit blog heeft een primaire sleutel van nul omdat de database nog geen echte sleutel voor de entiteit heeft gegenereerd.
- De 'ADO.NET Blog' is niet opgenomen in de lokale verzameling, ook al wordt deze nog steeds bijgehouden door de context. Dit komt doordat we het uit de DbSet hebben verwijderd, waardoor deze als verwijderd wordt gemarkeerd.
- Wanneer DbSet wordt gebruikt om een query uit te voeren die is gemarkeerd voor verwijdering (ADO.NET Blog) wordt opgenomen in de resultaten en wordt het nieuwe blog (Mijn nieuwe blog) dat nog niet in de database is opgeslagen, niet opgenomen in de resultaten. Dit komt doordat DbSet een query uitvoert op de database en de geretourneerde resultaten altijd weerspiegelen wat zich in de database bevindt.
Lokaal gebruiken om entiteiten toe te voegen aan en te verwijderen uit de context
De eigenschap Local op DbSet retourneert een ObservableCollection met gebeurtenissen die zijn gekoppeld, zodat deze gesynchroniseerd blijft met de inhoud van de context. Dit betekent dat entiteiten kunnen worden toegevoegd aan of verwijderd uit de lokale verzameling of de DbSet. Dit betekent ook dat query's die nieuwe entiteiten in de context brengen, ertoe leiden dat de lokale verzameling wordt bijgewerkt met die entiteiten. Voorbeeld:
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);
}
}
Ervan uitgaande dat we een paar berichten hebben getagd met 'entity-framework' en 'asp.net', ziet de uitvoer er ongeveer als volgt uit:
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
Dit illustreert drie punten:
- Het nieuwe bericht 'What's New in EF' dat is toegevoegd aan de lokale verzameling, wordt bijgehouden door de context in de status Toegevoegd. Deze wordt daarom ingevoegd in de database wanneer SaveChanges wordt aangeroepen.
- Het bericht dat is verwijderd uit de lokale verzameling (EF Beginners Guide) is nu gemarkeerd als verwijderd in de context. Deze wordt daarom verwijderd uit de database wanneer SaveChanges wordt aangeroepen.
- Het extra bericht (ASP.NET Beginnershandleiding) dat in de context wordt geladen met de tweede query, wordt automatisch toegevoegd aan de lokale verzameling.
Een laatste opmerking over Local is dat de prestaties, omdat het een ObservableCollection is, niet ideaal zijn voor grote aantallen entiteiten. Als u dus te maken hebt met duizenden entiteiten in uw context, is het wellicht niet raadzaam om Lokaal te gebruiken.
Lokaal gebruiken voor WPF-gegevensbinding
De eigenschap Local in DbSet kan rechtstreeks worden gebruikt voor gegevensbinding in een WPF-toepassing omdat het een exemplaar van ObservableCollection is. Zoals beschreven in de vorige secties betekent dit dat deze automatisch gesynchroniseerd blijft met de inhoud van de context en dat de inhoud van de context automatisch gesynchroniseerd blijft. Houd er rekening mee dat u de lokale verzameling vooraf moet invullen met gegevens om iets te binden, omdat Local nooit een databasequery veroorzaakt.
Dit is geen geschikte plaats voor een volledig WPF-gegevensbindingsvoorbeeld, maar de belangrijkste elementen zijn:
- Een bindingsbron instellen
- Bind het aan de eigenschap Local van uw set
- Vul Lokaal in met behulp van een query naar de database.
WPF-binding aan navigatie-eigenschappen
Als u hoofd-/detailgegevensbinding uitvoert, kunt u de detailweergave binden aan een navigatie-eigenschap van een van uw entiteiten. Een eenvoudige manier om dit werk te maken is door een ObservableCollection te gebruiken voor de navigatie-eigenschap. Voorbeeld:
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; }
}
}
Gebruik Local om entiteiten op te schonen tijdens SaveChanges
In de meeste gevallen worden entiteiten die zijn verwijderd uit een navigatie-eigenschap niet automatisch gemarkeerd als verwijderd in de context. Als u bijvoorbeeld een Post-object verwijdert uit de verzameling Blog.Posts, wordt dat bericht niet automatisch verwijderd wanneer SaveChanges wordt aangeroepen. Als u deze wilt verwijderen, moet u deze zwevende entiteiten mogelijk vinden en markeren als verwijderd voordat u SaveChanges aanroept of als onderdeel van een overschreven SaveChanges. Voorbeeld:
public override int SaveChanges()
{
foreach (var post in this.Posts.Local.ToList())
{
if (post.Blog == null)
{
this.Posts.Remove(post);
}
}
return base.SaveChanges();
}
De bovenstaande code maakt gebruik van de lokale verzameling om alle berichten te vinden en markeert alle berichten die geen blogreferentie hebben als verwijderd. De aanroep ToList is vereist omdat anders de verzameling wordt gewijzigd door de aanroep Remove terwijl deze wordt geïnventariseerd. In de meeste andere situaties kunt u rechtstreeks query's uitvoeren op de eigenschap Local zonder eerst ToList te gebruiken.
Het gebruiken van Local en ToBindingList voor Windows Forms-gegevensbinding
Windows Forms biedt geen ondersteuning voor volledige getrouwheid van gegevensbinding met ObservableCollection rechtstreeks. U kunt echter nog steeds de eigenschap DbSet Local gebruiken voor gegevensbinding om alle voordelen te krijgen die in de vorige secties worden beschreven. Dit wordt bereikt via de ToBindingList-extensiemethode waarmee een IBindingList-implementatie wordt gemaakt die wordt ondersteund door de Local ObservableCollection.
Dit is geen geschikte plaats voor een volledig voorbeeld van windows Forms-gegevensbinding, maar de belangrijkste elementen zijn:
- Een objectbindingsbron instellen
- Bind deze aan de eigenschap Local van uw set met behulp van Local.ToBindingList()
- Vul de lokale omgeving met behulp van een query naar de database
Gedetailleerde informatie over bijgehouden entiteiten ophalen
Veel van de voorbeelden in deze reeks gebruiken de methode Entry om een DbEntityEntry-exemplaar voor een entiteit te retourneren. Dit invoerobject fungeert vervolgens als uitgangspunt voor het verzamelen van informatie over de entiteit, zoals de huidige status, en voor het uitvoeren van bewerkingen op de entiteit, zoals het expliciet laden van een gerelateerde entiteit.
De Entries-methoden retourneren DbEntityEntry-objecten voor veel of alle entiteiten die door de context worden bijgehouden. Hiermee kunt u informatie verzamelen of bewerkingen uitvoeren op veel entiteiten in plaats van slechts één vermelding. Voorbeeld:
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);
}
}
U ziet dat we een klasse Auteur en Lezer introduceren in het voorbeeld. Beide klassen implementeren de 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; }
}
Stel dat we de volgende gegevens in de database hebben:
Blog met BlogId = 1 en Name = 'ADO.NET Blog'
Blog met BlogId = 2 en Name = 'The Visual Studio Blog'
Blog met BlogId = 3 en Name = '.NET Framework Blog'
Auteur met AuthorId = 1 en Naam = 'Joe Bloggs'
Lezer met ReaderId = 1 en Name = 'John Doe'
De uitvoer van het uitvoeren van de code is:
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
Deze voorbeelden illustreren verschillende punten:
- Met de invoermethoden worden vermeldingen geretourneerd voor entiteiten in alle staten, inclusief Verwijderd. Vergelijk dit met Lokaal, waarbij verwijderde entiteiten worden uitgesloten.
- Vermeldingen voor alle entiteitstypen worden geretourneerd wanneer de niet-generieke Entries-methode wordt gebruikt. Wanneer de methode algemene vermeldingen wordt gebruikt, worden alleen vermeldingen geretourneerd voor entiteiten die exemplaren van het algemene type zijn. Dit is hierboven gebruikt om inzendingen voor alle blogs op te halen. Het is ook gebruikt om vermeldingen op te halen voor alle entiteiten die IPerson implementeren. Dit laat zien dat het algemene type geen echt entiteitstype hoeft te zijn.
- LINQ naar objecten kan worden gebruikt om de geretourneerde resultaten te filteren. Dit is hierboven gebruikt om entiteiten van elk type te vinden zolang ze worden gewijzigd.
DbEntityEntry-exemplaren bevatten altijd een niet-null-entiteit. Relatie-vermeldingen en stub-vermeldingen worden niet weergegeven als DbEntityEntry-exemplaren, dus u hoeft hiervoor niet te filteren.