Hubungan, properti navigasi, dan kunci asing

Artikel ini memberikan gambaran umum tentang bagaimana Kerangka Kerja Entitas mengelola hubungan antar entitas. Ini juga memberikan beberapa panduan tentang cara memetakan dan memanipulasi hubungan.

Hubungan dalam EF

Dalam database relasional, hubungan (juga disebut asosiasi) antara tabel didefinisikan melalui kunci asing. Kunci asing (FK) adalah kolom atau kombinasi kolom yang digunakan untuk membuat dan menerapkan tautan antara data dalam dua tabel. Umumnya ada tiga jenis hubungan: satu-ke-satu, satu-ke-banyak, dan banyak-ke-banyak. Dalam hubungan satu ke banyak, kunci asing didefinisikan pada tabel yang mewakili banyak akhir hubungan. Hubungan banyak ke banyak melibatkan penentuan tabel ketiga (disebut persimpangan atau tabel penghubung), yang kunci utamanya terdiri dari kunci asing dari kedua tabel yang terkait. Dalam hubungan satu-ke-satu, kunci utama bertindak juga sebagai kunci asing dan tidak ada kolom kunci asing terpisah untuk salah satu tabel.

Gambar berikut menunjukkan dua tabel yang berpartisipasi dalam hubungan satu ke banyak. Tabel Kursus adalah tabel dependen karena berisi kolom DepartmentID yang menautkannya ke tabel Departemen .

Tabel Departemen dan Kursus

Dalam Kerangka Kerja Entitas, entitas dapat terkait dengan entitas lain melalui asosiasi atau hubungan. Setiap hubungan berisi dua ujung yang menjelaskan jenis entitas dan perkalian jenis (satu, nol atau satu, atau banyak) untuk dua entitas dalam hubungan tersebut. Hubungan dapat diatur oleh batasan referensial, yang menjelaskan bagian mana dalam hubungan merupakan peran yang utama dan mana yang merupakan peran yang bergantung.

Properti navigasi menyediakan cara untuk menavigasi asosiasi antara dua tipe entitas. Setiap objek dapat memiliki properti navigasi untuk setiap hubungan tempat objek berpartisipasi. Properti navigasi memungkinkan Anda menavigasi dan mengelola hubungan di kedua arah, mengembalikan objek referensi (jika perkalian adalah satu atau nol-atau-satu) atau koleksi (jika perkaliannya banyak). Anda juga dapat memilih untuk memiliki navigasi satu arah, dalam hal ini Anda menentukan properti navigasi hanya pada salah satu jenis yang berpartisipasi dalam hubungan dan bukan pada keduanya.

Disarankan untuk menyertakan properti dalam model yang terhubung ke kunci asing dalam database. Dengan termasuk properti kunci asing, Anda dapat membuat atau mengubah hubungan dengan memodifikasi nilai kunci asing pada objek dependen. Asosiasi semacam ini disebut asosiasi kunci asing. Menggunakan kunci asing bahkan lebih penting ketika bekerja dengan entitas yang terputus. Perhatikan bahwa saat bekerja dengan hubungan 1-ke-1 atau 1-ke-0..1, tidak ada kolom kunci asing yang terpisah; atribut kunci utama bertindak sebagai kunci asing dan selalu disertakan dalam model.

Ketika kolom kunci asing tidak disertakan dalam model, informasi asosiasi dikelola sebagai objek independen. Hubungan dilacak melalui referensi objek alih-alih properti kunci asing. Jenis asosiasi ini disebut asosiasi independen. Cara paling umum untuk memodifikasi asosiasi independen adalah dengan memodifikasi properti navigasi yang dihasilkan untuk setiap entitas yang berpartisipasi dalam asosiasi.

Anda dapat memilih untuk menggunakan satu atau kedua jenis asosiasi dalam model Anda. Namun, jika Anda memiliki hubungan banyak-ke-banyak murni yang dihubungkan oleh tabel gabungan yang hanya berisi kunci asing, Entity Framework (EF) akan menggunakan asosiasi yang berdiri sendiri untuk mengelola hubungan banyak-ke-banyak tersebut.   

Gambar berikut menunjukkan model konseptual yang dibuat dengan Perancang Kerangka Kerja Entitas. Model ini berisi dua entitas yang berpartisipasi dalam hubungan satu-ke-banyak. Kedua entitas memiliki properti navigasi. Kursus adalah entitas dependen dan memiliki properti kunci asing DepartmentID yang ditentukan.

Tabel Departemen dan Kursus dengan properti navigasi

Cuplikan kode berikut menunjukkan model yang sama yang dibuat dengan Code First.

public class Course
{
  public int CourseID { get; set; }
  public string Title { get; set; }
  public int Credits { get; set; }
  public int DepartmentID { get; set; }
  public virtual Department Department { get; set; }
}

public class Department
{
   public Department()
   {
     this.Courses = new HashSet<Course>();
   }  
   public int DepartmentID { get; set; }
   public string Name { get; set; }
   public decimal Budget { get; set; }
   public DateTime StartDate { get; set; }
   public int? Administrator {get ; set; }
   public virtual ICollection<Course> Courses { get; set; }
}

Mengonfigurasi atau memetakan hubungan

Sisa halaman ini mencakup cara mengakses dan memanipulasi data menggunakan hubungan. Untuk informasi tentang mengonfigurasi hubungan dalam model Anda, lihat halaman berikut.

Membuat dan memodifikasi hubungan

Dalam asosiasi kunci asing, ketika Anda mengubah hubungan, status objek dependen yang memiliki status EntityState.Unchanged akan berubah menjadi EntityState.Modified. Dalam hubungan independen, mengubah hubungan tidak memperbarui status objek dependen.

Contoh berikut menunjukkan cara menggunakan properti kunci asing dan properti navigasi untuk mengaitkan objek terkait. Dengan asosiasi kunci asing, Anda dapat menggunakan salah satu metode untuk mengubah, membuat, atau memodifikasi hubungan. Dengan asosiasi independen, Anda tidak dapat menggunakan properti kunci asing.

  • Dengan menetapkan nilai baru ke properti kunci asing, seperti dalam contoh berikut.

    course.DepartmentID = newCourse.DepartmentID;
    
  • Kode berikut menghapus hubungan dengan mengatur kunci asing ke null. Perhatikan, bahwa properti kunci asing harus nullable.

    course.DepartmentID = null;
    

    Nota

    Jika referensi dalam status ditambahkan (dalam contoh ini, objek kursus), properti navigasi referensi tidak akan disinkronkan dengan nilai kunci objek baru sampai SaveChanges dipanggil. Sinkronisasi tidak terjadi karena konteks objek tidak berisi kunci permanen untuk objek yang ditambahkan hingga disimpan. Jika Anda harus memiliki objek baru yang sepenuhnya disinkronkan segera setelah Anda mengatur hubungan, gunakan salah satu metode berikut.*

  • Dengan menetapkan objek baru ke properti navigasi. Kode berikut menciptakan hubungan antara kursus dan department. Jika objek dilampirkan ke konteks, course juga ditambahkan ke koleksi department.Courses, dan properti kunci asing pada objek course yang sesuai diatur ke nilai properti kunci departemen.

    course.Department = department;
    
  • Untuk menghapus hubungan, atur properti navigasi ke null. Jika Anda bekerja dengan Entity Framework yang didasarkan pada .NET 4.0, maka akhir terkait perlu dimuat sebelum Anda mengaturnya ke null. Contohnya:

    context.Entry(course).Reference(c => c.Department).Load();
    course.Department = null;
    

    Dimulai dengan Entity Framework 5.0, yang didasarkan pada .NET 4.5, Anda dapat mengatur hubungan ke null tanpa memuat akhir terkait. Anda juga dapat mengatur nilai saat ini ke null menggunakan metode berikut.

    context.Entry(course).Reference(c => c.Department).CurrentValue = null;
    
  • Dengan menghapus atau menambahkan objek dalam kumpulan entitas. Misalnya, Anda dapat menambahkan objek jenis Course ke department.Courses koleksi. Operasi ini menciptakan hubungan antara kursus tertentu dan department tertentu. Jika objek dilampirkan ke konteks, referensi departemen dan properti kunci asing pada objek kursus akan diatur ke yang sesuai department.

    department.Courses.Add(newCourse);
    
  • Dengan menggunakan ChangeRelationshipState metode untuk mengubah status hubungan yang ditentukan antara dua objek entitas. Metode ini paling umum digunakan saat bekerja dengan aplikasi N-Tingkat dan asosiasi independen (tidak dapat digunakan dengan asosiasi kunci asing). Selain itu, untuk menggunakan metode ini, Anda harus turun ke ObjectContext, seperti yang ditunjukkan pada contoh di bawah ini.
    Dalam contoh berikut, ada hubungan banyak ke banyak antara para Instruktur dan Kursus. Memanggil metode ChangeRelationshipState dan meneruskan parameter EntityState.Added, memberitahu SchoolContext bahwa hubungan telah ditambahkan antara kedua objek.

    
    ((IObjectContextAdapter)context).ObjectContext.
      ObjectStateManager.
      ChangeRelationshipState(course, instructor, c => c.Instructor, EntityState.Added);
    

    Perhatikan bahwa jika Anda memperbarui (bukan hanya menambahkan) hubungan, Anda harus menghapus hubungan lama setelah menambahkan yang baru:

    ((IObjectContextAdapter)context).ObjectContext.
      ObjectStateManager.
      ChangeRelationshipState(course, oldInstructor, c => c.Instructor, EntityState.Deleted);
    

Menyinkronkan perubahan antara kunci asing dan properti navigasi

Saat Anda mengubah hubungan objek yang dilampirkan ke konteks dengan menggunakan salah satu metode yang dijelaskan di atas, Kerangka Kerja Entitas perlu menjaga kunci asing, referensi, dan koleksi tetap sinkron. Entity Framework secara otomatis mengelola sinkronisasi ini (juga dikenal sebagai perbaikan hubungan) untuk entitas POCO dengan proksi. Untuk informasi selengkapnya, lihat Bekerja dengan Proksi.

Jika Anda menggunakan entitas POCO tanpa proksi, Anda harus memastikan bahwa metode DetectChanges dipanggil untuk menyinkronkan objek terkait dalam konteks. Perhatikan bahwa API berikut secara otomatis memicu panggilan DetectChanges .

  • DbSet.Add
  • DbSet.AddRange
  • DbSet.Remove
  • DbSet.RemoveRange
  • DbSet.Find
  • DbSet.Local
  • DbContext.SaveChanges
  • DbSet.Attach
  • DbContext.GetValidationErrors
  • DbContext.Entry
  • DbChangeTracker.Entries
  • Menjalankan kueri LINQ terhadap DbSet

Dalam Kerangka Kerja Entitas, Anda biasanya menggunakan properti navigasi untuk memuat entitas yang terkait dengan entitas yang dikembalikan oleh asosiasi yang ditentukan. Untuk informasi selengkapnya, lihat Memuat Objek Terkait.

Nota

Dalam asosiasi kunci asing, ketika Anda memuat akhir terkait dari objek dependen, objek terkait akan dimuat berdasarkan nilai kunci asing dependen yang saat ini berada dalam memori:

    // Get the course where currently DepartmentID = 2.
    Course course = context.Courses.First(c => c.DepartmentID == 2);

    // Use DepartmentID foreign key property
    // to change the association.
    course.DepartmentID = 3;

    // Load the related Department where DepartmentID = 3
    context.Entry(course).Reference(c => c.Department).Load();

Dalam asosiasi independen, akhir terkait objek dependen dikueri berdasarkan nilai kunci asing yang saat ini ada dalam database. Namun, jika hubungan dimodifikasi, dan properti referensi pada objek dependen menunjuk ke objek utama berbeda yang dimuat dalam konteks objek, Kerangka Kerja Entitas akan mencoba membuat hubungan seperti yang didefinisikan pada klien.

Mengelola konkurensi

Dalam asosiasi kunci asing dan independen, pemeriksaan konkurensi didasarkan pada kunci entitas dan properti entitas lain yang ditentukan dalam model. Saat menggunakan EF Designer untuk membuat model, atur ConcurrencyMode atribut ke tetap untuk menentukan bahwa properti harus diperiksa konkurensinya. Saat menggunakan Code First untuk menentukan model, gunakan ConcurrencyCheck anotasi pada atribut yang ingin Anda periksa untuk konkurensinya. Saat bekerja dengan Code First, Anda juga dapat menggunakan TimeStamp anotasi untuk menentukan bahwa properti harus diperiksa konkurensinya. Anda hanya dapat memiliki satu properti tanda waktu di kelas tertentu. Kode Pertama memetakan properti ini ke bidang yang tidak dapat diubah ke null dalam database.

Kami menyarankan agar Anda selalu menggunakan asosiasi kunci asing saat bekerja dengan entitas yang berpartisipasi dalam pemeriksaan dan resolusi konkurensi.

Untuk informasi selengkapnya, lihat Menangani Konflik Konkurensi.

Bekerja dengan Kunci yang tumpang tindih

Kunci yang tumpang tindih adalah kunci komposit di mana beberapa properti dalam kunci juga merupakan bagian dari kunci lain dalam entitas. Anda tidak dapat memiliki kunci yang tumpang tindih dalam asosiasi independen. Untuk mengubah asosiasi kunci asing yang mencakup kunci yang tumpang tindih, kami sarankan Anda memodifikasi nilai kunci asing alih-alih menggunakan referensi objek.