Bagikan melalui


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