Kode Pertama: Asosiasi independen vs. asosiasi kunci asing?

102

Saya memiliki debat mental dengan diri saya sendiri setiap kali saya mulai mengerjakan proyek baru dan saya merancang POCO saya. Saya telah melihat banyak tutorial / contoh kode yang tampaknya mendukung asosiasi kunci asing :

Asosiasi kunci asing

public class Order
{
    public int ID { get; set; }
    public int CustomerID { get; set; } // <-- Customer ID
    ...
}

Berbeda dengan asosiasi independen :

Asosiasi independen

public class Order
{
    public int ID { get; set; }
    public Customer Customer { get; set; } // <-- Customer object
    ...
}

Saya telah bekerja dengan NHibernate di masa lalu, dan menggunakan asosiasi independen, yang tidak hanya terasa lebih OO, tetapi juga (dengan pemuatan lambat) memiliki keuntungan untuk memberi saya akses ke seluruh objek Pelanggan, bukan hanya ID-nya. Ini memungkinkan saya, misalnya, mengambil instance Order dan kemudian melakukannya Order.Customer.FirstNametanpa harus melakukan penggabungan secara eksplisit, yang sangat memudahkan.

Jadi untuk rekap, pertanyaan saya adalah:

  1. Apakah ada kerugian yang signifikan dalam menggunakan asosiasi independen? dan...
  2. Jika tidak ada, apa alasan untuk menggunakan asosiasi kunci asing?
Daniel Liuzzi
sumber

Jawaban:

106

Jika Anda ingin memanfaatkan ORM sepenuhnya, Anda pasti akan menggunakan referensi Entitas:

public class Order
{
    public int ID { get; set; }
    public Customer Customer { get; set; } // <-- Customer object
    ...
}

Setelah Anda menghasilkan model entitas dari database dengan FK, itu akan selalu menghasilkan referensi entitas. Jika Anda tidak ingin menggunakannya, Anda harus mengubah file EDMX secara manual dan menambahkan properti yang mewakili FK. Setidaknya ini adalah kasus di Entity Framework v1 di mana hanya asosiasi Independen yang diizinkan.

Kerangka kerja entitas v4 menawarkan jenis asosiasi baru yang disebut Asosiasi kunci asing. Perbedaan paling jelas antara asosiasi kunci independen dan kunci asing ada di kelas Order:

public class Order
{
    public int ID { get; set; }
    public int CustomerId { get; set; }  // <-- Customer ID
    public Customer Customer { get; set; } // <-- Customer object
    ...
}

Seperti yang Anda lihat, Anda memiliki properti FK dan referensi entitas. Ada lebih banyak perbedaan antara dua jenis asosiasi:

Asosiasi independen

  • Ini direpresentasikan sebagai objek terpisah di ObjectStateManager. Itu punya sendiri EntityState!
  • Saat membangun asosiasi, Anda selalu membutuhkan hak dari kedua ujung asosiasi
  • Asosiasi ini dipetakan dengan cara yang sama seperti entitas.

Asosiasi kunci asing

  • Itu tidak direpresentasikan sebagai objek terpisah di ObjectStateManager. Karena itu Anda harus mengikuti beberapa aturan khusus.
  • Saat membangun asosiasi, Anda tidak membutuhkan kedua ujung asosiasi. Cukup memiliki entitas anak dan PK entitas induk tetapi nilai PK harus unik. Jadi saat menggunakan asosiasi kunci asing, Anda juga harus menetapkan ID unik sementara ke entitas yang baru dibuat yang digunakan dalam relasi.
  • Asosiasi ini tidak dipetakan tetapi mendefinisikan batasan referensial.

Jika Anda ingin menggunakan asosiasi kunci asing, Anda harus mencentang Sertakan kolom kunci asing dalam model di Panduan Model Data Entitas.

Edit:

Saya menemukan bahwa perbedaan antara kedua jenis asosiasi ini tidak terlalu dikenal, jadi saya menulis artikel singkat yang membahas hal ini dengan lebih detail dan pendapat saya sendiri tentang ini.

Ladislav Mrnka
sumber
Terima kasih atas jawaban Anda yang sangat berwawasan, dan juga atas pengertian tentang terminologi yang benar, yang membantu saya menemukan banyak sumber daya tentang subjek dan pro / kontra dari kedua teknik tersebut.
Daniel Liuzzi
1
Saya baru saja menemukan artikel Anda, Ladislav. Bacaan yang sangat menarik, dan sumber daya yang bagus untuk lebih memahami perbedaan antara kedua pendekatan ini. Bersulang.
Daniel Liuzzi
1
@ GaussZ: Seperti yang saya ketahui tidak ada perubahan dalam cara penanganan asosiasi sejak EF4 (di mana asosiasi FK diperkenalkan).
Ladislav Mrnka
1
Jawaban ini dan jawaban lainnya tampaknya tidak menyentuh masalah kinerja. Namun, menurut bagian 2.2 Faktor yang mempengaruhi kinerja Tampilan Pembuatan dari artikel MSDN, menggunakan Asosiasi Independen tampaknya meningkatkan biaya Pembuatan Tampilan atas asosiasi Kunci Asing.
Veverke
1
@LadislavMrnka: dapatkah Anda memeriksa ulang tautan ke artice yang Anda sebutkan di atas berfungsi? Saya tidak dapat mengaksesnya.
Veverke
34

Gunakan keduanya. Dan buat referensi entitas Anda menjadi virtual untuk memungkinkan pemuatan lambat. Seperti ini:

public class Order
{
  public int ID { get; set; }
  public int CustomerID { get; set; }
  public virtual Customer Customer { get; set; } // <-- Customer object
  ...
}

Ini menghemat pencarian DB yang tidak perlu, memungkinkan pemuatan lambat, dan memungkinkan Anda untuk dengan mudah melihat / mengatur ID jika Anda tahu apa yang Anda inginkan. Perhatikan bahwa memiliki keduanya tidak mengubah struktur tabel Anda dengan cara apa pun.

Seth Paulson
sumber
5
Sepakat. Inilah yang akhirnya saya lakukan, seperti yang disarankan Ladislav. Ini benar-benar memberi Anda yang terbaik dari kedua dunia; seluruh objek saat Anda membutuhkan semua propertinya, dan ID-nya saat Anda hanya membutuhkan PK dan tidak peduli dengan sisanya.
Daniel Liuzzi
9

Asosiasi independen tidak bekerja dengan baik AddOrUpdateyang biasanya digunakan dalam Seedmetode. Ketika referensi adalah item yang sudah ada, itu akan dimasukkan kembali.

// Existing customer.
var customer = new Customer { Id = 1, Name = "edit name" };
db.Set<Customer>().AddOrUpdate(customer);

// New order.
var order = new Order { Id = 1, Customer = customer };
db.Set<Order>().AddOrUpdate(order);

Hasilnya pelanggan lama akan dimasukkan kembali dan pelanggan baru (dimasukkan kembali) akan dikaitkan dengan pesanan baru.


Kecuali kita menggunakan asosiasi kunci asing dan menetapkan id.

 // Existing customer.
var customer = new Customer { Id = 1, Name = "edit name" };
db.Set<Customer>().AddOrUpdate(customer);

// New order.
var order = new Order { Id = 1, CustomerId = customer.Id };
db.Set<Order>().AddOrUpdate(order);

Kami memiliki perilaku yang diharapkan, pelanggan yang ada akan dikaitkan dengan pesanan baru.

Yuliam Chandra
sumber
2
Ini adalah penemuan yang bagus. Namun, penyelesaiannya (dan saya pikir cara yang tepat) untuk melampirkan pelanggan ke pesanan memuatnya dari konteks db seperti ini: var order = new Order { Id = 1, Customer = db.Customers.Find(1) }; Atau Anda dapat menggunakan metode Pilih untuk memuat pelanggan dari konteks db. Ini bekerja dengan asosiasi independen.
tala9999
4

Saya menyukai pendekatan objek untuk menghindari pencarian yang tidak perlu. Objek properti bisa dengan mudah diisi saat Anda memanggil metode pabrik untuk membangun seluruh entitas (menggunakan kode panggilan balik sederhana untuk entitas bertingkat). Tidak ada kerugian yang bisa saya lihat kecuali untuk penggunaan memori (tetapi Anda akan men-cache objek Anda, kan?). Jadi, semua yang Anda lakukan adalah mengganti tumpukan untuk heap dan mendapatkan keuntungan kinerja dari tidak melakukan pencarian. Saya harap ini masuk akal.

CarneyCode
sumber