Mengakses Entitas terlacak
Ada empat API utama untuk mengakses entitas yang DbContextdilacak oleh :
- DbContext.Entry mengembalikan instans untuk instans EntityEntry<TEntity> entitas tertentu.
- ChangeTracker.Entries mengembalikan instans EntityEntry<TEntity> untuk semua entitas terlacak, atau untuk semua entitas terlacak dari jenis tertentu.
- DbContext.Find, , DbContext.FindAsyncDbSet<TEntity>.Find, dan DbSet<TEntity>.FindAsync temukan satu entitas dengan kunci primer, pertama-tama cari di entitas yang dilacak, lalu kueri database jika diperlukan.
- DbSet<TEntity>.Local mengembalikan entitas aktual (bukan instans EntityEntry) untuk entitas jenis entitas yang diwakili oleh DbSet.
Masing-masing dijelaskan secara lebih rinci di bagian di bawah ini.
Tip
Dokumen ini mengasumsikan bahwa status entitas dan dasar-dasar pelacakan perubahan EF Core dipahami. Lihat Pelacakan Perubahan di EF Core untuk informasi selengkapnya tentang topik ini.
Tip
Anda dapat menjalankan dan men-debug ke semua kode dalam dokumen ini dengan mengunduh kode sampel dari GitHub.
Menggunakan instans DbContext.Entry dan EntityEntry
Untuk setiap entitas yang dilacak, Entity Framework Core (EF Core) melacak:
- Status keseluruhan entitas. Ini adalah salah satu dari
Unchanged
, ,Added
Modified
, atauDeleted
; lihat Pelacakan Perubahan di EF Core untuk informasi selengkapnya. - Hubungan antara entitas yang dilacak. Misalnya, blog tempat postingan berada.
- "Nilai saat ini" properti.
- "Nilai asli" properti, ketika informasi ini tersedia. Nilai asli adalah nilai properti yang ada saat entitas dikueri dari database.
- Nilai properti mana yang telah dimodifikasi sejak dikueri.
- Informasi lain tentang nilai properti, seperti apakah nilai tersebut bersifat sementara atau tidak.
Meneruskan instans entitas untuk DbContext.Entry menghasilkan memberikan EntityEntry<TEntity> akses ke informasi ini untuk entitas tertentu. Contohnya:
using var context = new BlogsContext();
var blog = context.Blogs.Single(e => e.Id == 1);
var entityEntry = context.Entry(blog);
Bagian berikut menunjukkan cara menggunakan EntityEntry untuk mengakses dan memanipulasi status entitas, serta status properti dan navigasi entitas.
Bekerja dengan entitas
Penggunaan EntityEntry<TEntity> yang paling umum adalah mengakses arus EntityState entitas. Contohnya:
var currentState = context.Entry(blog).State;
if (currentState == EntityState.Unchanged)
{
context.Entry(blog).State = EntityState.Modified;
}
Metode Entri juga dapat digunakan pada entitas yang belum dilacak. Ini tidak mulai melacak entitas; status entitas masih Detached
. Namun, EntityEntry yang dikembalikan kemudian dapat digunakan untuk mengubah status entitas, di mana entitas akan dilacak dalam status tertentu. Misalnya, kode berikut akan mulai melacak instans Blog sebagai 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
Tidak seperti di EF6, mengatur status entitas individu tidak akan menyebabkan semua entitas yang terhubung dilacak. Ini membuat pengaturan status dengan cara ini operasi tingkat lebih rendah daripada memanggil Add
, , Attach
atau Update
, yang beroperasi pada seluruh grafik entitas.
Tabel berikut ini meringkas cara menggunakan EntityEntry untuk bekerja dengan seluruh entitas:
Anggota EntityEntry | Deskripsi |
---|---|
EntityEntry.State | Mendapatkan dan mengatur EntityState entitas. |
EntityEntry.Entity | Mendapatkan instans entitas. |
EntityEntry.Context | Yang DbContext melacak entitas ini. |
EntityEntry.Metadata | IEntityType metadata untuk jenis entitas. |
EntityEntry.IsKeySet | Apakah entitas telah menetapkan nilai kuncinya atau tidak. |
EntityEntry.Reload() | Menimpa nilai properti dengan nilai yang dibaca dari database. |
EntityEntry.DetectChanges() | Memaksa deteksi perubahan untuk entitas ini saja; lihat Deteksi Perubahan dan Pemberitahuan. |
Bekerja dengan satu properti
Beberapa kelebihan beban EntityEntry<TEntity>.Property izinkan akses ke informasi tentang properti individual entitas. Misalnya, menggunakan API yang sangat ditik, seperti fasih:
PropertyEntry<Blog, string> propertyEntry = context.Entry(blog).Property(e => e.Name);
Nama properti dapat diteruskan sebagai string. Contohnya:
PropertyEntry<Blog, string> propertyEntry = context.Entry(blog).Property<string>("Name");
Yang dikembalikan PropertyEntry<TEntity,TProperty> kemudian dapat digunakan untuk mengakses informasi tentang properti . Misalnya, dapat digunakan untuk mendapatkan dan mengatur nilai properti saat ini pada entitas ini:
string currentValue = context.Entry(blog).Property(e => e.Name).CurrentValue;
context.Entry(blog).Property(e => e.Name).CurrentValue = "1unicorn2";
Kedua metode Properti yang digunakan di atas mengembalikan instans generik PropertyEntry<TEntity,TProperty> yang sangat ditik. Menggunakan jenis generik ini lebih disukai karena memungkinkan akses ke nilai properti tanpa jenis nilai tinju. Namun, jika jenis entitas atau properti tidak diketahui pada waktu kompilasi, maka non-generik PropertyEntry dapat diperoleh sebagai gantinya:
PropertyEntry propertyEntry = context.Entry(blog).Property("Name");
Ini memungkinkan akses ke informasi properti untuk properti apa pun terlepas dari jenisnya, dengan mengorbankan jenis nilai tinju. Contohnya:
object blog = context.Blogs.Single(e => e.Id == 1);
object currentValue = context.Entry(blog).Property("Name").CurrentValue;
context.Entry(blog).Property("Name").CurrentValue = "1unicorn2";
Tabel berikut ini meringkas informasi properti yang diekspos oleh PropertyEntry:
Anggota PropertyEntry | Deskripsi |
---|---|
PropertyEntry<TEntity,TProperty>.CurrentValue | Mendapatkan dan mengatur nilai properti saat ini. |
PropertyEntry<TEntity,TProperty>.OriginalValue | Mendapatkan dan mengatur nilai asli properti, jika tersedia. |
PropertyEntry<TEntity,TProperty>.EntityEntry | Referensi kembali ke EntityEntry<TEntity> untuk entitas. |
PropertyEntry.Metadata | IProperty metadata untuk properti . |
PropertyEntry.IsModified | Menunjukkan apakah properti ini ditandai sebagai dimodifikasi, dan memungkinkan status ini diubah. |
PropertyEntry.IsTemporary | Menunjukkan apakah properti ini ditandai sebagai sementara, dan memungkinkan status ini diubah. |
Catatan:
- Nilai asli properti adalah nilai yang dimiliki properti saat entitas dikueri dari database. Namun, nilai asli tidak tersedia jika entitas terputus dan kemudian secara eksplisit dilampirkan ke DbContext lain, misalnya dengan
Attach
atauUpdate
. Dalam hal ini, nilai asli yang dikembalikan akan sama dengan nilai saat ini. - SaveChanges hanya akan memperbarui properti yang ditandai sebagai dimodifikasi. Atur IsModified ke true untuk memaksa EF Core memperbarui nilai properti tertentu, atau mengaturnya ke false untuk mencegah EF Core memperbarui nilai properti.
- Nilai sementara biasanya dihasilkan oleh generator nilai EF Core. Mengatur nilai properti saat ini akan menggantikan nilai sementara dengan nilai yang diberikan dan menandai properti sebagai bukan sementara. Atur IsTemporary ke true untuk memaksa nilai menjadi sementara bahkan setelah ditetapkan secara eksplisit.
Bekerja dengan satu navigasi
Beberapa kelebihan beban EntityEntry<TEntity>.Reference, EntityEntry<TEntity>.Collection, dan EntityEntry.Navigation memungkinkan akses ke informasi tentang navigasi individual.
Navigasi referensi ke satu entitas terkait diakses melalui Reference metode . Navigasi referensi menunjuk ke sisi "satu" dari hubungan satu-ke-banyak, dan kedua sisi hubungan satu-ke-satu. Contohnya:
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");
Navigasi juga dapat menjadi kumpulan entitas terkait ketika digunakan untuk sisi "banyak" dari hubungan satu-ke-banyak dan banyak-ke-banyak. Metode Collection ini digunakan untuk mengakses navigasi pengumpulan. Contohnya:
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");
Beberapa operasi umum untuk semua navigasi. Ini dapat diakses untuk navigasi referensi dan pengumpulan menggunakan EntityEntry.Navigation metode . Perhatikan bahwa hanya akses non-generik yang tersedia saat mengakses semua navigasi bersama-sama. Contohnya:
NavigationEntry navigationEntry = context.Entry(blog).Navigation("Posts");
Tabel berikut ini meringkas cara menggunakan ReferenceEntry<TEntity,TProperty>, , CollectionEntry<TEntity,TRelatedEntity>dan NavigationEntry:
Anggota NavigationEntry | Deskripsi |
---|---|
MemberEntry.CurrentValue | Mendapatkan dan mengatur nilai navigasi saat ini. Ini adalah seluruh koleksi untuk navigasi koleksi. |
NavigationEntry.Metadata | INavigationBase metadata untuk navigasi. |
NavigationEntry.IsLoaded | Mendapatkan atau menetapkan nilai yang menunjukkan apakah entitas atau koleksi terkait telah dimuat sepenuhnya dari database. |
NavigationEntry.Load() | Memuat entitas atau koleksi terkait dari database; lihat Pemuatan Eksplisit Data Terkait. |
NavigationEntry.Query() | Kueri yang akan digunakan EF Core untuk memuat navigasi ini sebagai IQueryable yang dapat disusupi lebih lanjut; lihat Pemuatan Eksplisit Data Terkait. |
Bekerja dengan semua properti entitas
EntityEntry.Properties mengembalikan dari IEnumerable<T> PropertyEntry untuk setiap properti entitas. Ini dapat digunakan untuk melakukan tindakan untuk setiap properti entitas. Misalnya, untuk mengatur properti DateTime apa pun ke DateTime.Now
:
foreach (var propertyEntry in context.Entry(blog).Properties)
{
if (propertyEntry.Metadata.ClrType == typeof(DateTime))
{
propertyEntry.CurrentValue = DateTime.Now;
}
}
Selain itu, EntityEntry berisi beberapa metode untuk mendapatkan dan mengatur semua nilai properti secara bersamaan. Metode ini menggunakan PropertyValues kelas , yang mewakili kumpulan properti dan nilainya. PropertyValues dapat diperoleh untuk nilai saat ini atau asli, atau untuk nilai seperti yang saat ini disimpan dalam database. Contohnya:
var currentValues = context.Entry(blog).CurrentValues;
var originalValues = context.Entry(blog).OriginalValues;
var databaseValues = context.Entry(blog).GetDatabaseValues();
Objek PropertyValues ini tidak terlalu berguna sendiri. Namun, mereka dapat dikombinasikan untuk melakukan operasi umum yang diperlukan saat memanipulasi entitas. Ini berguna saat bekerja dengan objek transfer data dan ketika menyelesaikan konflik konkurensi optimis. Bagian berikut menunjukkan beberapa contoh.
Mengatur nilai saat ini atau asli dari entitas atau DTO
Nilai entitas saat ini atau asli dapat diperbarui dengan menyalin nilai dari objek lain. Misalnya, pertimbangkan BlogDto
objek transfer data (DTO) dengan properti yang sama dengan jenis entitas:
public class BlogDto
{
public int Id { get; set; }
public string Name { get; set; }
}
Ini dapat digunakan untuk mengatur nilai saat ini dari entitas yang dilacak menggunakan PropertyValues.SetValues:
var blogDto = new BlogDto { Id = 1, Name = "1unicorn2" };
context.Entry(blog).CurrentValues.SetValues(blogDto);
Teknik ini terkadang digunakan saat memperbarui entitas dengan nilai yang diperoleh dari panggilan layanan atau klien dalam aplikasi n-tingkat. Perhatikan bahwa objek yang digunakan tidak harus berjenis sama dengan entitas selama memiliki properti yang namanya cocok dengan entitas. Dalam contoh di atas, instans DTO BlogDto
digunakan untuk mengatur nilai entitas yang dilacak Blog
saat ini.
Perhatikan bahwa properti hanya akan ditandai sebagai dimodifikasi jika set nilai berbeda dari nilai saat ini.
Mengatur nilai saat ini atau asli dari kamus
Contoh sebelumnya menetapkan nilai dari entitas atau instans DTO. Perilaku yang sama tersedia ketika nilai properti disimpan sebagai pasangan nama/nilai dalam kamus. Contohnya:
var blogDictionary = new Dictionary<string, object> { ["Id"] = 1, ["Name"] = "1unicorn2" };
context.Entry(blog).CurrentValues.SetValues(blogDictionary);
Mengatur nilai saat ini atau asli dari database
Nilai entitas saat ini atau asli dapat diperbarui dengan nilai terbaru dari database dengan memanggil GetDatabaseValues() atau GetDatabaseValuesAsync dan menggunakan objek yang dikembalikan untuk mengatur nilai saat ini atau asli, atau keduanya. Contohnya:
var databaseValues = context.Entry(blog).GetDatabaseValues();
context.Entry(blog).CurrentValues.SetValues(databaseValues);
context.Entry(blog).OriginalValues.SetValues(databaseValues);
Membuat objek kloning yang berisi nilai saat ini, asli, atau database
Objek PropertyValues yang dikembalikan dari CurrentValues, OriginalValues, atau GetDatabaseValues dapat digunakan untuk membuat klon entitas menggunakan PropertyValues.ToObject(). Contohnya:
var clonedBlog = context.Entry(blog).GetDatabaseValues().ToObject();
Perhatikan bahwa ToObject
mengembalikan instans baru yang tidak dilacak oleh DbContext. Objek yang dikembalikan juga tidak memiliki hubungan apa pun yang diatur ke entitas lain.
Objek kloning dapat berguna untuk menyelesaikan masalah yang terkait dengan pembaruan bersamaan ke database, terutama ketika pengikatan data ke objek dari jenis tertentu. Lihat konkurensi optimis untuk informasi selengkapnya.
Bekerja dengan semua navigasi entitas
EntityEntry.Navigations mengembalikan dari IEnumerable<T> NavigationEntry untuk setiap navigasi entitas. EntityEntry.References dan EntityEntry.Collections melakukan hal yang sama, tetapi dibatasi untuk navigasi referensi atau pengumpulan masing-masing. Ini dapat digunakan untuk melakukan tindakan untuk setiap navigasi entitas. Misalnya, untuk memaksa pemuatan semua entitas terkait:
foreach (var navigationEntry in context.Entry(blog).Navigations)
{
navigationEntry.Load();
}
Bekerja dengan semua anggota entitas
Properti reguler dan properti navigasi memiliki status dan perilaku yang berbeda. Oleh karena itu, umum untuk memproses navigasi dan non-navigasi secara terpisah, seperti yang ditunjukkan pada bagian di atas. Namun, terkadang dapat berguna untuk melakukan sesuatu dengan anggota entitas mana pun, terlepas dari apakah itu properti atau navigasi biasa. EntityEntry.Member dan EntityEntry.Members disediakan untuk tujuan ini. Contohnya:
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}");
}
Menjalankan kode ini di blog dari sampel menghasilkan output berikut:
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
Tampilan debug pelacak perubahan menampilkan informasi seperti ini. Tampilan debug untuk seluruh pelacak perubahan dihasilkan dari individu EntityEntry.DebugView dari setiap entitas yang dilacak.
Temukan dan FindAsync
DbContext.Find, , DbContext.FindAsyncDbSet<TEntity>.Find, dan DbSet<TEntity>.FindAsync dirancang untuk pencarian yang efisien dari satu entitas ketika kunci utamanya diketahui. Temukan pemeriksaan pertama apakah entitas sudah dilacak, dan jika demikian segera mengembalikan entitas. Kueri database hanya dibuat jika entitas tidak dilacak secara lokal. Misalnya, pertimbangkan kode ini yang memanggil Temukan dua kali untuk entitas yang sama:
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.");
Output dari kode ini (termasuk pengelogan EF Core) saat menggunakan SQLite adalah:
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.
Perhatikan bahwa panggilan pertama tidak menemukan entitas secara lokal dan menjalankan kueri database. Sebaliknya, panggilan kedua mengembalikan instans yang sama tanpa mengkueri database karena sudah dilacak.
Temukan mengembalikan null jika entitas dengan kunci yang diberikan tidak dilacak secara lokal dan tidak ada di database.
Kunci komposit
Temukan juga dapat digunakan dengan kunci komposit. Misalnya, pertimbangkan OrderLine
entitas dengan kunci komposit yang terdiri dari ID pesanan dan ID produk:
public class OrderLine
{
public int OrderId { get; set; }
public int ProductId { get; set; }
//...
}
Kunci komposit harus dikonfigurasi DbContext.OnModelCreating untuk menentukan bagian kunci dan urutannya. Contohnya:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder
.Entity<OrderLine>()
.HasKey(e => new { e.OrderId, e.ProductId });
}
Perhatikan bahwa OrderId
adalah bagian pertama dari kunci dan ProductId
merupakan bagian kedua dari kunci. Urutan ini harus digunakan saat meneruskan nilai kunci ke Temukan. Contohnya:
var orderline = context.OrderLines.Find(orderId, productId);
Menggunakan ChangeTracker.Entries untuk mengakses semua entitas yang dilacak
Sejauh ini kami hanya mengakses satu per satu EntityEntry . ChangeTracker.Entries() mengembalikan EntityEntry untuk setiap entitas yang saat ini dilacak oleh DbContext. Contohnya:
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}");
}
Kode ini menghasilkan output berikut:
Found Blog entity with ID 1
Found Post entity with ID 1
Found Post entity with ID 2
Perhatikan bahwa entri untuk blog dan posting dikembalikan. Hasilnya dapat difilter ke jenis entitas tertentu menggunakan ChangeTracker.Entries<TEntity>() kelebihan beban umum:
foreach (var entityEntry in context.ChangeTracker.Entries<Post>())
{
Console.WriteLine(
$"Found {entityEntry.Metadata.Name} entity with ID {entityEntry.Property(e => e.Id).CurrentValue}");
}
Output dari kode ini menunjukkan bahwa hanya posting yang dikembalikan:
Found Post entity with ID 1
Found Post entity with ID 2
Selain itu, menggunakan kelebihan beban umum mengembalikan instans generik EntityEntry<TEntity> . Inilah yang memungkinkan akses seperti fasih ke Id
properti dalam contoh ini.
Jenis generik yang digunakan untuk pemfilteran tidak harus menjadi jenis entitas yang dipetakan; jenis dasar atau antarmuka yang tidak dipetakan dapat digunakan sebagai gantinya. Misalnya, jika semua jenis entitas dalam model menerapkan antarmuka yang menentukan properti kuncinya:
public interface IEntityWithKey
{
int Id { get; set; }
}
Kemudian antarmuka ini dapat digunakan untuk bekerja dengan kunci entitas apa pun yang dilacak dengan cara yang sangat ditik. Contohnya:
foreach (var entityEntry in context.ChangeTracker.Entries<IEntityWithKey>())
{
Console.WriteLine(
$"Found {entityEntry.Metadata.Name} entity with ID {entityEntry.Property(e => e.Id).CurrentValue}");
}
Menggunakan DbSet.Local untuk mengkueri entitas yang dilacak
Kueri EF Core selalu dijalankan pada database, dan hanya mengembalikan entitas yang telah disimpan ke database. DbSet<TEntity>.Local menyediakan mekanisme untuk mengkueri DbContext untuk entitas lokal yang dilacak.
Karena DbSet.Local
digunakan untuk mengkueri entitas yang dilacak, biasanya memuat entitas ke dalam DbContext lalu bekerja dengan entitas yang dimuat tersebut. Ini terutama berlaku untuk pengikatan data, tetapi juga dapat berguna dalam situasi lain. Misalnya, dalam kode berikut database pertama kali dikueri untuk semua blog dan postingan. Metode Load ekstensi digunakan untuk menjalankan kueri ini dengan hasil yang dilacak oleh konteks tanpa dikembalikan langsung ke aplikasi. (Menggunakan ToList
atau serupa memiliki efek yang sama tetapi dengan overhead pembuatan daftar yang dikembalikan, yang tidak diperlukan di sini.) Contoh kemudian menggunakan DbSet.Local
untuk mengakses entitas yang dilacak secara lokal:
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}");
}
Perhatikan bahwa, tidak seperti ChangeTracker.Entries(), DbSet.Local
mengembalikan instans entitas secara langsung. EntitasEntry dapat, tentu saja, selalu diperoleh untuk entitas yang dikembalikan dengan memanggil DbContext.Entry.
Tampilan lokal
DbSet<TEntity>.Local mengembalikan tampilan entitas yang dilacak secara lokal yang mencerminkan entitas tersebut saat ini EntityState . Secara khusus, ini berarti bahwa:
Added
entitas disertakan. Perhatikan bahwa ini bukan kasus untuk kueri EF Core normal, karenaAdded
entitas belum ada dalam database dan karena itu tidak pernah dikembalikan oleh kueri database.Deleted
entitas dikecualikan. Perhatikan bahwa ini sekali lagi tidak terjadi untuk kueri EF Core normal, karenaDeleted
entitas masih ada dalam database dan sebagainya dikembalikan oleh kueri database.
Semua ini berarti bahwa DbSet.Local
melihat data yang mencerminkan status konseptual grafik entitas saat ini, dengan Added
entitas disertakan dan Deleted
entitas dikecualikan. Ini cocok dengan status database apa yang diharapkan setelah SaveChanges dipanggil.
Ini biasanya tampilan ideal untuk pengikatan data, karena disajikan kepada pengguna data karena mereka memahaminya berdasarkan perubahan yang dibuat oleh aplikasi.
Kode berikut menunjukkan ini dengan menandai satu postingan sebagai Deleted
lalu menambahkan postingan baru, menandainya sebagai 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}");
}
Output dari kode ini adalah:
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
Perhatikan bahwa postingan yang dihapus dihapus dari tampilan lokal, dan postingan yang ditambahkan disertakan.
Menggunakan Lokal untuk menambahkan dan menghapus entitas
DbSet<TEntity>.Local mengembalikan instans dari LocalView<TEntity>. Ini adalah implementasi dari ICollection<T> yang menghasilkan dan merespons pemberitahuan ketika entitas ditambahkan dan dihapus dari koleksi. (Ini adalah konsep yang sama dengan ObservableCollection<T>, tetapi diimplementasikan sebagai proyeksi atas entri pelacakan perubahan Inti EF yang ada, bukan sebagai koleksi independen.)
Pemberitahuan tampilan lokal dikaitkan ke pelacakan perubahan DbContext sehingga tampilan lokal tetap sinkron dengan DbContext. Khususnya:
- Menambahkan entitas baru menyebabkannya
DbSet.Local
dilacak oleh DbContext, biasanya dalam statusAdded
. (Jika entitas sudah memiliki nilai kunci yang dihasilkan, maka entitas tersebut dilacak sebagaiUnchanged
gantinya.) - Menghapus entitas dari
DbSet.Local
penyebabnya ditandai sebagaiDeleted
. - Entitas yang dilacak oleh DbContext akan secara otomatis muncul dalam
DbSet.Local
koleksi. Misalnya, menjalankan kueri untuk membawa lebih banyak entitas secara otomatis menyebabkan tampilan lokal diperbarui. - Entitas yang ditandai sebagai
Deleted
akan dihapus dari koleksi lokal secara otomatis.
Ini berarti tampilan lokal dapat digunakan untuk memanipulasi entitas yang dilacak hanya dengan menambahkan dan menghapus dari koleksi. Misalnya, mari kita ubah kode contoh sebelumnya untuk menambahkan dan menghapus postingan dari koleksi lokal:
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}");
}
Output tetap tidak berubah dari contoh sebelumnya karena perubahan yang dilakukan pada tampilan lokal disinkronkan dengan DbContext.
Menggunakan tampilan lokal untuk pengikatan data Formulir Windows atau WPF
DbSet<TEntity>.Local membentuk dasar untuk pengikatan data ke entitas EF Core. Namun, baik Formulir Windows maupun WPF berfungsi paling baik saat digunakan dengan jenis tertentu untuk memberi tahu koleksi yang mereka harapkan. Tampilan lokal mendukung pembuatan jenis koleksi khusus ini:
- LocalView<TEntity>.ToObservableCollection()ObservableCollection<T> mengembalikan untuk pengikatan data WPF.
- LocalView<TEntity>.ToBindingList()BindingList<T> mengembalikan untuk pengikatan data Formulir Windows.
Contohnya:
ObservableCollection<Post> observableCollection = context.Posts.Local.ToObservableCollection();
BindingList<Post> bindingList = context.Posts.Local.ToBindingList();
Lihat Mulai menggunakan WPF untuk informasi selengkapnya tentang pengikatan data WPF dengan EF Core, dan Mulai menggunakan Formulir Windows untuk informasi selengkapnya tentang pengikatan data Formulir Windows dengan EF Core.
Tip
Tampilan lokal untuk instans DbSet tertentu dibuat dengan malas saat pertama kali diakses lalu di-cache. Pembuatan LocalView itu sendiri cepat dan tidak menggunakan memori yang signifikan. Namun, itu memanggil DetectChanges, yang dapat lambat untuk sejumlah besar entitas. Koleksi yang dibuat oleh ToObservableCollection
dan ToBindingList
juga dibuat dengan malas dan kemudian di-cache. Kedua metode ini membuat koleksi baru, yang bisa lambat dan menggunakan banyak memori ketika ribuan entitas terlibat.