Bekerja dengan nilai properti
Untuk sebagian besar Kerangka Kerja Entitas akan mengurus pelacakan status, nilai asli, dan nilai saat ini dari properti instans entitas Anda. Namun, mungkin ada beberapa kasus - seperti skenario terputus - di mana Anda ingin melihat atau memanipulasi informasi yang dimiliki EF tentang properti. Teknik yang ditunjukkan dalam topik ini berlaku sama untuk model yang dibuat dengan Perancang EF dan Code First.
Kerangka Kerja Entitas melacak dua nilai untuk setiap properti entitas yang dilacak. Nilai saat ini adalah, seperti namanya, nilai properti saat ini dalam entitas. Nilai asli adalah nilai yang dimiliki properti saat entitas dikueri dari database atau dilampirkan ke konteks.
Ada dua mekanisme umum untuk bekerja dengan nilai properti:
- Nilai properti tunggal dapat diperoleh dengan cara yang sangat ditik menggunakan metode Properti.
- Nilai untuk semua properti entitas dapat dibaca ke dalam objek DbPropertyValues. DbPropertyValues kemudian bertindak sebagai objek seperti kamus untuk memungkinkan nilai properti dibaca dan diatur. Nilai dalam objek DbPropertyValues dapat diatur dari nilai di objek DbPropertyValues lain atau dari nilai di beberapa objek lain, seperti salinan entitas lain atau objek transfer data sederhana (DTO).
Bagian di bawah ini menunjukkan contoh penggunaan kedua mekanisme di atas.
Mendapatkan dan mengatur nilai properti individual saat ini atau asli
Contoh di bawah ini menunjukkan bagaimana nilai properti saat ini dapat dibaca lalu diatur ke nilai baru:
using (var context = new BloggingContext())
{
var blog = context.Blogs.Find(3);
// Read the current value of the Name property
string currentName1 = context.Entry(blog).Property(u => u.Name).CurrentValue;
// Set the Name property to a new value
context.Entry(blog).Property(u => u.Name).CurrentValue = "My Fancy Blog";
// Read the current value of the Name property using a string for the property name
object currentName2 = context.Entry(blog).Property("Name").CurrentValue;
// Set the Name property to a new value using a string for the property name
context.Entry(blog).Property("Name").CurrentValue = "My Boring Blog";
}
Gunakan properti OriginalValue alih-alih properti CurrentValue untuk membaca atau mengatur nilai asli.
Perhatikan bahwa nilai yang dikembalikan di ketik sebagai "objek" saat string digunakan untuk menentukan nama properti. Di sisi lain, nilai yang dikembalikan sangat di ketik jika ekspresi lambda digunakan.
Mengatur nilai properti seperti ini hanya akan menandai properti sebagai dimodifikasi jika nilai baru berbeda dari nilai lama.
Ketika nilai properti diatur dengan cara ini perubahan secara otomatis terdeteksi meskipun AutoDetectChanges dinonaktifkan.
Mendapatkan dan mengatur nilai properti yang tidak dipetakan saat ini
Nilai properti saat ini yang tidak dipetakan ke database juga dapat dibaca. Contoh properti yang tidak dipetakan bisa menjadi properti RssLink di Blog. Nilai ini dapat dihitung berdasarkan BlogId, dan karena itu tidak perlu disimpan dalam database. Contohnya:
using (var context = new BloggingContext())
{
var blog = context.Blogs.Find(1);
// Read the current value of an unmapped property
var rssLink = context.Entry(blog).Property(p => p.RssLink).CurrentValue;
// Use a string to specify the property name
var rssLinkAgain = context.Entry(blog).Property("RssLink").CurrentValue;
}
Nilai saat ini juga dapat diatur jika properti mengekspos setter.
Membaca nilai properti yang tidak dipetakan berguna saat melakukan validasi Kerangka Kerja Entitas dari properti yang tidak dipetakan. Untuk alasan yang sama, nilai saat ini dapat dibaca dan diatur untuk properti entitas yang saat ini tidak dilacak oleh konteks. Contohnya:
using (var context = new BloggingContext())
{
// Create an entity that is not being tracked
var blog = new Blog { Name = "ADO.NET Blog" };
// Read and set the current value of Name as before
var currentName1 = context.Entry(blog).Property(u => u.Name).CurrentValue;
context.Entry(blog).Property(u => u.Name).CurrentValue = "My Fancy Blog";
var currentName2 = context.Entry(blog).Property("Name").CurrentValue;
context.Entry(blog).Property("Name").CurrentValue = "My Boring Blog";
}
Perhatikan bahwa nilai asli tidak tersedia untuk properti yang tidak dipetakan atau untuk properti entitas yang tidak dilacak oleh konteks.
Memeriksa apakah properti ditandai sebagai dimodifikasi
Contoh di bawah ini menunjukkan cara memeriksa apakah properti individual ditandai sebagai dimodifikasi atau tidak:
using (var context = new BloggingContext())
{
var blog = context.Blogs.Find(1);
var nameIsModified1 = context.Entry(blog).Property(u => u.Name).IsModified;
// Use a string for the property name
var nameIsModified2 = context.Entry(blog).Property("Name").IsModified;
}
Nilai properti yang dimodifikasi dikirim sebagai pembaruan untuk database saat SaveChanges dipanggil.
Menandai properti sebagai dimodifikasi
Contoh di bawah ini menunjukkan cara memaksa properti individual ditandai sebagai dimodifikasi:
using (var context = new BloggingContext())
{
var blog = context.Blogs.Find(1);
context.Entry(blog).Property(u => u.Name).IsModified = true;
// Use a string for the property name
context.Entry(blog).Property("Name").IsModified = true;
}
Menandai properti sebagai dimodifikasi memaksa pembaruan untuk dikirim ke database untuk properti saat SaveChanges dipanggil bahkan jika nilai properti saat ini sama dengan nilai aslinya.
Saat ini tidak dimungkinkan untuk mengatur ulang properti individual agar tidak dimodifikasi setelah ditandai sebagai dimodifikasi. Ini adalah sesuatu yang kami rencanakan untuk didukung dalam rilis mendatang.
Membaca nilai saat ini, asli, dan database untuk semua properti entitas
Contoh di bawah ini menunjukkan cara membaca nilai saat ini, nilai asli, dan nilai yang sebenarnya dalam database untuk semua properti entitas yang dipetakan.
using (var context = new BloggingContext())
{
var blog = context.Blogs.Find(1);
// Make a modification to Name in the tracked entity
blog.Name = "My Cool Blog";
// Make a modification to Name in the database
context.Database.SqlCommand("update dbo.Blogs set Name = 'My Boring Blog' where Id = 1");
// Print out current, original, and database values
Console.WriteLine("Current values:");
PrintValues(context.Entry(blog).CurrentValues);
Console.WriteLine("\nOriginal values:");
PrintValues(context.Entry(blog).OriginalValues);
Console.WriteLine("\nDatabase values:");
PrintValues(context.Entry(blog).GetDatabaseValues());
}
public static void PrintValues(DbPropertyValues values)
{
foreach (var propertyName in values.PropertyNames)
{
Console.WriteLine("Property {0} has value {1}",
propertyName, values[propertyName]);
}
}
Nilai saat ini adalah nilai yang saat ini dimuat properti entitas. Nilai asli adalah nilai yang dibaca dari database saat entitas dikueri. Nilai database adalah nilai karena saat ini disimpan dalam database. Mendapatkan nilai database berguna ketika nilai dalam database mungkin telah berubah sejak entitas dikueri seperti ketika pengeditan bersamaan ke database telah dibuat oleh pengguna lain.
Mengatur nilai saat ini atau asli dari objek lain
Nilai saat ini atau asli dari entitas terlacak dapat diperbarui dengan menyalin nilai dari objek lain. Contohnya:
using (var context = new BloggingContext())
{
var blog = context.Blogs.Find(1);
var coolBlog = new Blog { Id = 1, Name = "My Cool Blog" };
var boringBlog = new BlogDto { Id = 1, Name = "My Boring Blog" };
// Change the current and original values by copying the values from other objects
var entry = context.Entry(blog);
entry.CurrentValues.SetValues(coolBlog);
entry.OriginalValues.SetValues(boringBlog);
// Print out current and original values
Console.WriteLine("Current values:");
PrintValues(entry.CurrentValues);
Console.WriteLine("\nOriginal values:");
PrintValues(entry.OriginalValues);
}
public class BlogDto
{
public int Id { get; set; }
public string Name { get; set; }
}
Menjalankan kode di atas akan mencetak:
Current values:
Property Id has value 1
Property Name has value My Cool Blog
Original values:
Property Id has value 1
Property Name has value My Boring Blog
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 BlogDTO digunakan untuk memperbarui nilai asli.
Perhatikan bahwa hanya properti yang diatur ke nilai yang berbeda saat disalin dari objek lain yang akan ditandai sebagai dimodifikasi.
Mengatur nilai saat ini atau asli dari kamus
Nilai saat ini atau asli dari entitas yang dilacak dapat diperbarui dengan menyalin nilai dari kamus atau beberapa struktur data lainnya. Contohnya:
using (var context = new BloggingContext())
{
var blog = context.Blogs.Find(1);
var newValues = new Dictionary<string, object>
{
{ "Name", "The New ADO.NET Blog" },
{ "Url", "blogs.msdn.com/adonet" },
};
var currentValues = context.Entry(blog).CurrentValues;
foreach (var propertyName in newValues.Keys)
{
currentValues[propertyName] = newValues[propertyName];
}
PrintValues(currentValues);
}
Gunakan properti OriginalValues alih-alih properti CurrentValues untuk mengatur nilai asli.
Mengatur nilai saat ini atau asli dari kamus menggunakan Properti
Alternatif untuk menggunakan CurrentValues atau OriginalValues seperti yang ditunjukkan di atas adalah dengan menggunakan metode Properti untuk mengatur nilai setiap properti. Ini dapat lebih disukai ketika Anda perlu mengatur nilai properti kompleks. Contohnya:
using (var context = new BloggingContext())
{
var user = context.Users.Find("johndoe1987");
var newValues = new Dictionary<string, object>
{
{ "Name", "John Doe" },
{ "Location.City", "Redmond" },
{ "Location.State.Name", "Washington" },
{ "Location.State.Code", "WA" },
};
var entry = context.Entry(user);
foreach (var propertyName in newValues.Keys)
{
entry.Property(propertyName).CurrentValue = newValues[propertyName];
}
}
Dalam contoh properti kompleks di atas diakses menggunakan nama putus-putus. Untuk cara lain mengakses properti kompleks, lihat dua bagian nanti dalam topik ini khusus tentang properti kompleks.
Membuat objek kloning yang berisi nilai saat ini, asli, atau database
Objek DbPropertyValues yang dikembalikan dari CurrentValues, OriginalValues, atau GetDatabaseValues dapat digunakan untuk membuat klon entitas. Kloning ini akan berisi nilai properti dari objek DbPropertyValues yang digunakan untuk membuatnya. Contohnya:
using (var context = new BloggingContext())
{
var blog = context.Blogs.Find(1);
var clonedBlog = context.Entry(blog).GetDatabaseValues().ToObject();
}
Perhatikan bahwa objek yang dikembalikan bukan entitas dan tidak dilacak oleh konteks. Objek yang dikembalikan juga tidak memiliki hubungan yang diatur ke objek lain.
Objek kloning dapat berguna untuk menyelesaikan masalah yang terkait dengan pembaruan bersamaan ke database, terutama di mana UI yang melibatkan pengikatan data ke objek dari jenis tertentu sedang digunakan.
Mendapatkan dan mengatur nilai properti kompleks saat ini atau asli
Nilai seluruh objek kompleks dapat dibaca dan diatur menggunakan metode Properti seperti halnya untuk properti primitif. Selain itu, Anda dapat menelusuri paling detail objek kompleks dan membaca atau mengatur properti objek tersebut, atau bahkan objek berlapis. Berikut adalah beberapa contoh:
using (var context = new BloggingContext())
{
var user = context.Users.Find("johndoe1987");
// Get the Location complex object
var location = context.Entry(user)
.Property(u => u.Location)
.CurrentValue;
// Get the nested State complex object using chained calls
var state1 = context.Entry(user)
.ComplexProperty(u => u.Location)
.Property(l => l.State)
.CurrentValue;
// Get the nested State complex object using a single lambda expression
var state2 = context.Entry(user)
.Property(u => u.Location.State)
.CurrentValue;
// Get the nested State complex object using a dotted string
var state3 = context.Entry(user)
.Property("Location.State")
.CurrentValue;
// Get the value of the Name property on the nested State complex object using chained calls
var name1 = context.Entry(user)
.ComplexProperty(u => u.Location)
.ComplexProperty(l => l.State)
.Property(s => s.Name)
.CurrentValue;
// Get the value of the Name property on the nested State complex object using a single lambda expression
var name2 = context.Entry(user)
.Property(u => u.Location.State.Name)
.CurrentValue;
// Get the value of the Name property on the nested State complex object using a dotted string
var name3 = context.Entry(user)
.Property("Location.State.Name")
.CurrentValue;
}
Gunakan properti OriginalValue alih-alih properti CurrentValue untuk mendapatkan atau mengatur nilai asli.
Perhatikan bahwa properti atau metode ComplexProperty dapat digunakan untuk mengakses properti yang kompleks. Namun, metode ComplexProperty harus digunakan jika Anda ingin menelusuri paling detail objek kompleks dengan panggilan Property atau ComplexProperty tambahan.
Menggunakan DbPropertyValues untuk mengakses properti kompleks
Saat Anda menggunakan CurrentValues, OriginalValues, atau GetDatabaseValues untuk mendapatkan semua nilai saat ini, asli, atau database untuk entitas, nilai properti kompleks apa pun dikembalikan sebagai objek DbPropertyValues berlapis. Objek berlapis ini kemudian dapat digunakan untuk mendapatkan nilai objek kompleks. Misalnya, metode berikut akan mencetak nilai semua properti, termasuk nilai properti kompleks apa pun dan properti kompleks berlapis.
public static void WritePropertyValues(string parentPropertyName, DbPropertyValues propertyValues)
{
foreach (var propertyName in propertyValues.PropertyNames)
{
var nestedValues = propertyValues[propertyName] as DbPropertyValues;
if (nestedValues != null)
{
WritePropertyValues(parentPropertyName + propertyName + ".", nestedValues);
}
else
{
Console.WriteLine("Property {0}{1} has value {2}",
parentPropertyName, propertyName,
propertyValues[propertyName]);
}
}
}
Untuk mencetak semua nilai properti saat ini, metode akan dipanggil seperti ini:
using (var context = new BloggingContext())
{
var user = context.Users.Find("johndoe1987");
WritePropertyValues("", context.Entry(user).CurrentValues);
}