Přístup ke sledovaným entitě
Existují čtyři hlavní rozhraní API pro přístup k entitám sledovaným pomocí DbContext:
- DbContext.Entry vrátí instanci pro danou EntityEntry<TEntity> instanci entity.
- ChangeTracker.Entries vrátí EntityEntry<TEntity> instance pro všechny sledované entity nebo pro všechny sledované entity daného typu.
- DbContext.Find, DbContext.FindAsync, DbSet<TEntity>.Finda DbSet<TEntity>.FindAsync vyhledejte jednu entitu podle primárního klíče, nejprve vyhledejte sledované entity a v případě potřeby dotazujte databázi.
- DbSet<TEntity>.Local vrátí skutečné entity (nikoli instance EntityEntry) pro entity typu entity reprezentované DbSet.
Každý z nich je podrobněji popsán v následujících částech.
Tip
Tento dokument předpokládá, že stavy entit a základy sledování změn EF Core jsou srozumitelné. Další informace o těchto tématech najdete v tématu Sledování změn v EF Core .
Tip
Celý kód v tomto dokumentu můžete spustit a ladit tak, že si stáhnete ukázkový kód z GitHubu.
Použití instancí DbContext.Entry a EntityEntry
U každé sledované entity sleduje Entity Framework Core (EF Core):
- Celkový stav entity. Toto je jedna z hodnot , , nebo
Deleted
; viz Change Tracking v EF Core dalšíAdded
informace.Modified
Unchanged
- Vztahy mezi sledovanými entitami. Například blog, do kterého příspěvek patří.
- "Aktuální hodnoty" vlastností.
- "Původní hodnoty" vlastností, pokud jsou tyto informace k dispozici. Původní hodnoty jsou hodnoty vlastností, které existovaly, když byla entita dotazována z databáze.
- Které hodnoty vlastností byly změněny od doby, kdy byly dotazovány.
- Další informace o hodnotách vlastností, například zda je hodnota dočasná.
Předání instance entity, aby DbContext.Entry výsledkem bylo EntityEntry<TEntity> poskytnutí přístupu k tomuto informacím pro danou entitu. Příklad:
using var context = new BlogsContext();
var blog = context.Blogs.Single(e => e.Id == 1);
var entityEntry = context.Entry(blog);
Následující části ukazují, jak pomocí EntityEntry přistupovat ke stavu entity a manipulovat s nimi a také se stavem vlastností a navigace entity.
Práce s entitou
Nejběžnějším použitím EntityEntry<TEntity> je přístup k aktuálnímu EntityState stavu entity. Příklad:
var currentState = context.Entry(blog).State;
if (currentState == EntityState.Unchanged)
{
context.Entry(blog).State = EntityState.Modified;
}
Metodu Entry lze použít také u entit, které ještě nejsou sledovány. Tím se nezačne sledovat entitu; stav entity je stále Detached
. Vrácená entita EntityEntry se pak dá použít ke změně stavu entity, v jakém okamžiku se entita bude sledovat v daném stavu. Například následující kód začne sledovat instanci blogu jako Added
:
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);
Tip
Na rozdíl od EF6 nastavení stavu jednotlivé entity nezpůsobí sledování všech propojených entit. Tím se nastaví stav tímto způsobem jako operace nižší úrovně než volání Add
, Attach
nebo Update
, které pracují s celým grafem entit.
Následující tabulka shrnuje způsoby použití EntityEntry k práci s celou entitou:
EntityEntry – člen | Popis |
---|---|
EntityEntry.State | Získá a nastaví EntityState entitu. |
EntityEntry.Entity | Získá instanci entity. |
EntityEntry.Context | Tato entita DbContext sleduje. |
EntityEntry.Metadata | IEntityType metadata pro typ entity. |
EntityEntry.IsKeySet | Určuje, jestli má entita nastavenou hodnotu klíče. |
EntityEntry.Reload() | Přepíše hodnoty vlastností hodnotami načtenými z databáze. |
EntityEntry.DetectChanges() | Vynutí detekci změn pouze pro tuto entitu; viz Detekce změn a oznámení. |
Práce s jednou vlastností
Několik přetížení EntityEntry<TEntity>.Property povolení přístupu k informacím o individuální vlastnosti entity. Například použití rozhraní API se silným typem, fluent-like:
PropertyEntry<Blog, string> propertyEntry = context.Entry(blog).Property(e => e.Name);
Název vlastnosti lze místo toho předat jako řetězec. Příklad:
PropertyEntry<Blog, string> propertyEntry = context.Entry(blog).Property<string>("Name");
PropertyEntry<TEntity,TProperty> Vrácená vlastnost se pak dá použít pro přístup k informacím o vlastnosti. Dá se například použít k získání a nastavení aktuální hodnoty vlastnosti u této entity:
string currentValue = context.Entry(blog).Property(e => e.Name).CurrentValue;
context.Entry(blog).Property(e => e.Name).CurrentValue = "1unicorn2";
Obě metody vlastnosti použité výše vrátí obecnou instanci silného typu PropertyEntry<TEntity,TProperty> . Použití tohoto obecného typu je upřednostňované, protože umožňuje přístup k hodnotám vlastností bez krabicových typů hodnot. Pokud však typ entity nebo vlastnosti není v době kompilace znám, lze místo toho získat jiný než obecný PropertyEntry :
PropertyEntry propertyEntry = context.Entry(blog).Property("Name");
To umožňuje přístup k informacím o vlastnosti pro libovolnou vlastnost bez ohledu na její typ, a to na úkor krabicových hodnotových typů. Příklad:
object blog = context.Blogs.Single(e => e.Id == 1);
object currentValue = context.Entry(blog).Property("Name").CurrentValue;
context.Entry(blog).Property("Name").CurrentValue = "1unicorn2";
Následující tabulka shrnuje informace o vlastnosti vystavené propertyEntry:
PropertyEntry – člen | Popis |
---|---|
PropertyEntry<TEntity,TProperty>.CurrentValue | Získá a nastaví aktuální hodnotu vlastnosti. |
PropertyEntry<TEntity,TProperty>.OriginalValue | Získá a nastaví původní hodnotu vlastnosti, pokud je k dispozici. |
PropertyEntry<TEntity,TProperty>.EntityEntry | Zpětný odkaz na entitu EntityEntry<TEntity> . |
PropertyEntry.Metadata | IProperty metadata vlastnosti. |
PropertyEntry.IsModified | Určuje, zda je tato vlastnost označena jako změněna, a umožňuje změnit tento stav. |
PropertyEntry.IsTemporary | Určuje, zda je tato vlastnost označena jako dočasná, a umožňuje změnit tento stav. |
Poznámky:
- Původní hodnota vlastnosti je hodnota, kterou vlastnost měla při dotazování entity z databáze. Původní hodnoty však nejsou k dispozici, pokud byla entita odpojena a explicitně připojena k jiné dbContext, například s
Attach
neboUpdate
. V tomto případě bude vrácená původní hodnota stejná jako aktuální hodnota. - SaveChanges aktualizuje pouze vlastnosti označené jako změněné. Nastavte IsModified hodnotu true, aby EF Core aktualizovala danou hodnotu vlastnosti, nebo ji nastavte na false, aby ef Core nemohla aktualizovat hodnotu vlastnosti.
- Dočasné hodnoty se obvykle generují generátory hodnot EF Core. Nastavení aktuální hodnoty vlastnosti nahradí dočasnou hodnotu danou hodnotou a označí vlastnost jako ne dočasnou. Hodnota IsTemporary true se nastaví tak, aby byla hodnota dočasná i po explicitní sadě.
Práce s jednou navigací
Několik přetížení EntityEntry<TEntity>.Reference, EntityEntry<TEntity>.Collectiona EntityEntry.Navigation povolit přístup k informacím o individuální navigaci.
Referenční navigace k jedné související entitě jsou přístupné prostřednictvím Reference metod. Odkazy na navigace ukazují na stranu "jedna" relací 1:N a obě strany relací 1:1. Příklad:
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");
Navigace můžou být také kolekce souvisejících entit, pokud se používají pro strany "N" relací 1:N a M:N. Metody Collection se používají pro přístup k navigaci v kolekci. Příklad:
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");
Některé operace jsou společné pro všechny navigace. K těmto odkazům i k navigaci kolekcí je možné získat přístup pomocí EntityEntry.Navigation metody. Mějte na paměti, že při společném přístupu ke všem navigačním panelům je k dispozici pouze ne generický přístup. Příklad:
NavigationEntry navigationEntry = context.Entry(blog).Navigation("Posts");
Následující tabulka shrnuje způsoby použití ReferenceEntry<TEntity,TProperty>, CollectionEntry<TEntity,TRelatedEntity>a NavigationEntry:
Člen NavigationEntry | Popis |
---|---|
MemberEntry.CurrentValue | Získá a nastaví aktuální hodnotu navigace. Toto je celá kolekce pro navigaci v kolekcích. |
NavigationEntry.Metadata | INavigationBase metadata pro navigaci. |
NavigationEntry.IsLoaded | Získá nebo nastaví hodnotu určující, zda související entita nebo kolekce byla plně načtena z databáze. |
NavigationEntry.Load() | Načte související entitu nebo kolekci z databáze; Viz Explicitní načítání souvisejících dat. |
NavigationEntry.Query() | Dotaz EF Core by použil k načtení této navigace jako IQueryable objektu, který se dá dále skládat. Viz Explicitní načítání souvisejících dat. |
Práce se všemi vlastnostmi entity
EntityEntry.Properties vrátí hodnotu IEnumerable<T> PropertyEntry pro každou vlastnost entity. Dá se použít k provedení akce pro každou vlastnost entity. Pokud například chcete nastavit libovolnou vlastnost DateTime na DateTime.Now
:
foreach (var propertyEntry in context.Entry(blog).Properties)
{
if (propertyEntry.Metadata.ClrType == typeof(DateTime))
{
propertyEntry.CurrentValue = DateTime.Now;
}
}
Kromě toho EntityEntry obsahuje několik metod pro získání a nastavení všech hodnot vlastností najednou. Tyto metody používají PropertyValues třídu, která představuje kolekci vlastností a jejich hodnot. VlastnostiValue lze získat pro aktuální nebo původní hodnoty nebo pro hodnoty, které jsou aktuálně uloženy v databázi. Příklad:
var currentValues = context.Entry(blog).CurrentValues;
var originalValues = context.Entry(blog).OriginalValues;
var databaseValues = context.Entry(blog).GetDatabaseValues();
Tyto Objekty PropertyValues nejsou samy o sobě velmi užitečné. Lze je ale zkombinovat a provádět běžné operace potřebné při manipulaci s entitami. To je užitečné při práci s objekty přenosu dat a při řešení optimistických konfliktů souběžnosti. V následujících částech najdete několik příkladů.
Nastavení aktuálních nebo původních hodnot z entity nebo DTO
Aktuální nebo původní hodnoty entity lze aktualizovat zkopírováním hodnot z jiného objektu. Představte si BlogDto
například objekt přenosu dat (DTO) se stejnými vlastnostmi jako typ entity:
public class BlogDto
{
public int Id { get; set; }
public string Name { get; set; }
}
To lze použít k nastavení aktuálních hodnot sledované entity pomocí PropertyValues.SetValues:
var blogDto = new BlogDto { Id = 1, Name = "1unicorn2" };
context.Entry(blog).CurrentValues.SetValues(blogDto);
Tato technika se někdy používá při aktualizaci entity s hodnotami získanými z volání služby nebo klienta v n-vrstvé aplikaci. Všimněte si, že použitý objekt nemusí být stejného typu jako entita, pokud má vlastnosti, jejichž názvy odpovídají názvům entity. V předchozím příkladu se instance DTO BlogDto
používá k nastavení aktuálních hodnot sledované Blog
entity.
Všimněte si, že vlastnosti se označí jako změněné, pouze pokud se sada hodnot liší od aktuální hodnoty.
Nastavení aktuálních nebo původních hodnot ze slovníku
Předchozí příklad nastavil hodnoty z entity nebo instance DTO. Stejné chování je k dispozici, pokud jsou hodnoty vlastností uloženy jako páry název/hodnota ve slovníku. Příklad:
var blogDictionary = new Dictionary<string, object> { ["Id"] = 1, ["Name"] = "1unicorn2" };
context.Entry(blog).CurrentValues.SetValues(blogDictionary);
Nastavení aktuálních nebo původních hodnot z databáze
Aktuální nebo původní hodnoty entity lze aktualizovat nejnovějšími hodnotami z databáze voláním GetDatabaseValues() nebo GetDatabaseValuesAsync použitím vráceného objektu k nastavení aktuálních nebo původních hodnot nebo obojího. Příklad:
var databaseValues = context.Entry(blog).GetDatabaseValues();
context.Entry(blog).CurrentValues.SetValues(databaseValues);
context.Entry(blog).OriginalValues.SetValues(databaseValues);
Vytvoření klonovaného objektu obsahujícího aktuální, původní nebo databázové hodnoty
PropertyValues objekt vrácený z CurrentValues, OriginalValues nebo GetDatabaseValues lze použít k vytvoření klon entity pomocí PropertyValues.ToObject(). Příklad:
var clonedBlog = context.Entry(blog).GetDatabaseValues().ToObject();
Všimněte si, že ToObject
vrátí novou instanci, která není sledována DbContext. Vrácený objekt také nemá žádné relace nastavené na jiné entity.
Klonovaný objekt může být užitečný pro řešení problémů souvisejících se souběžnými aktualizacemi databáze, zejména při datové vazbě k objektům určitého typu. Další informace najdete v tématu optimistická souběžnost .
Práce se všemi navigacemi entity
EntityEntry.Navigations vrátí hodnotu IEnumerable<T> NavigationEntry pro každou navigaci entity. EntityEntry.References a EntityEntry.Collections udělej to samé, ale omezuje se na odkazy nebo navigaci v kolekci. Dá se použít k provedení akce pro každou navigaci entity. Pokud například chcete vynutit načítání všech souvisejících entit:
foreach (var navigationEntry in context.Entry(blog).Navigations)
{
navigationEntry.Load();
}
Práce se všemi členy entity
Běžné vlastnosti a navigační vlastnosti mají jiný stav a chování. Proto je běžné zpracovávat navigace a navigace, které nejsou navigačními prvky samostatně, jak je znázorněno v předchozích částech. Někdy ale může být užitečné něco udělat s libovolným členem entity bez ohledu na to, jestli se jedná o běžnou vlastnost nebo navigaci. EntityEntry.Member a EntityEntry.Members jsou k tomuto účelu poskytovány. Příklad:
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}");
}
Spuštění tohoto kódu na blogu z ukázky vygeneruje následující výstup:
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]
Tip
Ladicí zobrazení sledování změn zobrazuje podobné informace. Zobrazení ladění pro celé sledování změn se generuje z jednotlivých EntityEntry.DebugView sledovaných entit.
Najít a najítsync
DbContext.FindDbSet<TEntity>.Find, DbContext.FindAsync, a DbSet<TEntity>.FindAsync jsou navrženy pro efektivní vyhledávání jedné entity, pokud je jeho primární klíč známý. Nejprve zjistí, jestli je entita již sledována, a pokud ano, vrátí entitu okamžitě. Databázový dotaz se vytvoří pouze v případě, že entita není sledována místně. Představte si například tento kód, který volá funkci Najít dvakrát pro stejnou entitu:
using var context = new BlogsContext();
Console.WriteLine("First call to Find...");
var blog1 = context.Blogs.Find(1);
Console.WriteLine($"...found blog {blog1.Name}");
Console.WriteLine();
Console.WriteLine("Second call to Find...");
var blog2 = context.Blogs.Find(1);
Debug.Assert(blog1 == blog2);
Console.WriteLine("...returned the same instance without executing a query.");
Výstup z tohoto kódu (včetně protokolování EF Core) při použití SQLite je:
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.
Všimněte si, že první volání nenajde entitu místně a proto spustí databázový dotaz. Druhé volání naopak vrátí stejnou instanci bez dotazování databáze, protože je již sledována.
Funkce Najít vrátí hodnotu null, pokud entita s daným klíčem není sledována místně a v databázi neexistuje.
Složené klávesy
Funkce Najít se dá použít také se složenými klíči. Představte si například entitu OrderLine
se složeným klíčem, který se skládá z ID objednávky a ID produktu:
public class OrderLine
{
public int OrderId { get; set; }
public int ProductId { get; set; }
//...
}
Složený klíč musí být nakonfigurovaný DbContext.OnModelCreating tak, aby definoval klíčové části a jejich pořadí. Příklad:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder
.Entity<OrderLine>()
.HasKey(e => new { e.OrderId, e.ProductId });
}
Všimněte si, že OrderId
je první částí klíče a ProductId
je druhou částí klíče. Toto pořadí se musí použít při předávání hodnot klíče do funkce Najít. Příklad:
var orderline = context.OrderLines.Find(orderId, productId);
Použití ChangeTracker.Entries pro přístup ke všem sledovaným entitám
Zatím jsme přistupovali pouze k jednomu EntityEntry najednou. ChangeTracker.Entries() vrátí EntityEntry pro každou entitu, která je aktuálně sledována DbContext. Příklad:
using var context = new BlogsContext();
var blogs = context.Blogs.Include(e => e.Posts).ToList();
foreach (var entityEntry in context.ChangeTracker.Entries())
{
Console.WriteLine($"Found {entityEntry.Metadata.Name} entity with ID {entityEntry.Property("Id").CurrentValue}");
}
Tento kód vygeneruje následující výstup:
Found Blog entity with ID 1
Found Post entity with ID 1
Found Post entity with ID 2
Všimněte si, že se vrátí položky pro blogy i příspěvky. Místo toho lze výsledky filtrovat podle konkrétního ChangeTracker.Entries<TEntity>() typu entity pomocí obecného přetížení:
foreach (var entityEntry in context.ChangeTracker.Entries<Post>())
{
Console.WriteLine(
$"Found {entityEntry.Metadata.Name} entity with ID {entityEntry.Property(e => e.Id).CurrentValue}");
}
Výstup z tohoto kódu ukazuje, že se vrátí pouze příspěvky:
Found Post entity with ID 1
Found Post entity with ID 2
Použití obecného přetížení také vrací obecné EntityEntry<TEntity> instance. To je to, co umožňuje, aby fluent-like přístup k vlastnosti v tomto příkladu Id
.
Obecný typ použitý pro filtrování nemusí být mapovaným typem entity; Místo toho lze použít nemapovaný základní typ nebo rozhraní. Pokud například všechny typy entit v modelu implementují rozhraní definující jejich klíčovou vlastnost:
public interface IEntityWithKey
{
int Id { get; set; }
}
Toto rozhraní lze použít k práci s klíčem jakékoli sledované entity silným typem. Příklad:
foreach (var entityEntry in context.ChangeTracker.Entries<IEntityWithKey>())
{
Console.WriteLine(
$"Found {entityEntry.Metadata.Name} entity with ID {entityEntry.Property(e => e.Id).CurrentValue}");
}
Použití DbSet.Local k dotazování sledovaných entit
Dotazy EF Core se vždy spouštějí v databázi a vrací pouze entity, které byly uloženy do databáze. DbSet<TEntity>.Local poskytuje mechanismus dotazování DbContext pro místní sledované entity.
Vzhledem k tomu DbSet.Local
, že se používá k dotazování sledovaných entit, je typické načíst entity do DbContext a pak pracovat s těmito načtenými entitami. To platí zejména pro datové vazby, ale může být užitečné i v jiných situacích. Například v následujícím kódu se databáze nejprve dotazuje na všechny blogy a příspěvky. Metoda Load rozšíření se používá ke spuštění tohoto dotazu s výsledky sledovanými kontextem, aniž by se vrátila přímo do aplikace. (Použití ToList
nebo podobné má stejný účinek, ale s režií na vytvoření vráceného seznamu, který zde není potřeba.) Příklad pak používá DbSet.Local
přístup k místně sledovaným entitě:
using var context = new BlogsContext();
context.Blogs.Include(e => e.Posts).Load();
foreach (var blog in context.Blogs.Local)
{
Console.WriteLine($"Blog: {blog.Name}");
}
foreach (var post in context.Posts.Local)
{
Console.WriteLine($"Post: {post.Title}");
}
Všimněte si, že na rozdíl od ChangeTracker.Entries()funkce vrátí DbSet.Local
instance entity přímo. EntityEntry lze samozřejmě vždy získat pro vrácenou entitu voláním DbContext.Entry.
Místní zobrazení
DbSet<TEntity>.Local vrátí zobrazení místně sledovaných entit, které odráží aktuální hodnoty EntityState těchto entit. Konkrétně to znamená, že:
Added
jsou zahrnuty entity. Všimněte si, že to není případ běžných dotazů EF Core, protožeAdded
entity ještě v databázi neexistují, a proto se nikdy nevrací databázovým dotazem.Deleted
entity jsou vyloučeny. Všimněte si, že to opět není případ normálních dotazů EF Core, protožeDeleted
entity stále existují v databázi, a proto jsou vráceny databázovými dotazy.
To vše znamená, že DbSet.Local
se jedná o zobrazení dat, která odrážejí aktuální koncepční stav grafu entit s entitami zahrnutými Added
a Deleted
vyloučenými entitami. To odpovídá očekávanému stavu databáze po zavolání SaveChanges.
Toto je obvykle ideální zobrazení pro datovou vazbu, protože prezentuje uživateli data tak, jak jim rozumí na základě změn provedených aplikací.
Následující kód ukazuje, že označí jeden příspěvek jako Deleted
a pak přidá nový příspěvek, označí ho jako Added
:
using var context = new BlogsContext();
var posts = context.Posts.Include(e => e.Blog).ToList();
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}");
}
Výstupem tohoto kódu je:
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
Všimněte si, že odstraněný příspěvek se odebere z místního zobrazení a přidaný příspěvek je zahrnutý.
Přidání a odebrání entit pomocí místního
DbSet<TEntity>.Localvrátí instanci .LocalView<TEntity> Jedná se o implementaci ICollection<T> , která generuje oznámení a reaguje na ně při přidání a odebrání entit z kolekce. (Jedná se o stejný koncept, ale ObservableCollection<T>implementovaný jako projekce stávajících položek sledování změn EF Core, nikoli jako nezávislá kolekce.)
Oznámení místního zobrazení jsou připojená ke sledování změn DbContext, aby místní zobrazení zůstalo synchronizované s DbContext. Konkrétně:
- Přidání nové entity, která
DbSet.Local
způsobí, že ji bude sledovat DbContext, obvykle veAdded
stavu. (Pokud už entita má vygenerovanou hodnotu klíče, sleduje se jakoUnchanged
.) - Odebrání entity z
DbSet.Local
důvodů, že bude označena jakoDeleted
. - V kolekci se automaticky zobrazí
DbSet.Local
entita, která bude sledována dbContextem. Například spuštěním dotazu, aby se přinesly další entity, se místní zobrazení automaticky aktualizuje. - Entita označená jako
Deleted
bude automaticky odebrána z místní kolekce.
To znamená, že místní zobrazení lze použít k manipulaci se sledovanými entitami jednoduše přidáním a odebráním z kolekce. Pojďme například upravit předchozí ukázkový kód tak, aby přidával a odebíral příspěvky z místní kolekce:
using var context = new BlogsContext();
var posts = context.Posts.Include(e => e.Blog).ToList();
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}");
}
Výstup zůstane beze změny z předchozího příkladu, protože změny provedené v místním zobrazení se synchronizují s DbContext.
Použití místního zobrazení pro datové vazby model Windows Forms nebo WPF
DbSet<TEntity>.Local tvoří základ pro datové vazby k entitám EF Core. Model Windows Forms i WPF ale fungují nejlépe při použití s konkrétním typem upozorňování kolekce, že očekávají. Místní zobrazení podporuje vytváření těchto konkrétních typů kolekcí:
- LocalView<TEntity>.ToObservableCollection() vrátí pro datovou ObservableCollection<T> vazbu WPF.
- LocalView<TEntity>.ToBindingList()BindingList<T> vrátí pro model Windows Forms datovou vazbu.
Příklad:
ObservableCollection<Post> observableCollection = context.Posts.Local.ToObservableCollection();
BindingList<Post> bindingList = context.Posts.Local.ToBindingList();
Další informace o datové vazbě WPF s EF Core najdete v tématu Začínáme s WPF a začínáme s model Windows Forms další informace o model Windows Forms datové vazbě s EF Core.
Tip
Místní zobrazení pro danou instanci DbSet se vytvoří lazily při prvním přístupu a pak v mezipaměti. Vytvoření LocalView je rychlé a nepoužívá významnou paměť. Volá ale DetectChanges, což může být pomalé u velkého počtu entit. Kolekce vytvořené ToObservableCollection
a ToBindingList
také se vytvářejí lazily a pak se ukládají do mezipaměti. Obě tyto metody vytvářejí nové kolekce, které můžou být pomalé a používají spoustu paměti, když jsou zapojeny tisíce entit.