MVC3'te Code First Entity Framework (4.1) Kullanarak Yabancı Anahtar İlişkilerini Nasıl Bildirmeliyim?


104

İlk olarak EF 4.1 kodunu kullanarak yabancı anahtar ilişkilerini ve diğer kısıtlamaları nasıl bildireceğime dair kaynakları arıyordum. Temel olarak veri modelini kodda oluşturuyorum ve bu modeli sorgulamak için MVC3 kullanıyorum. Her şey harika olan MVC üzerinden çalışıyor (Microsoft'a şükürler olsun!) Ama şimdi çalışmamasını istiyorum çünkü veri modeli kısıtlamalarına ihtiyacım var.

Örneğin, harici nesneler (tablolar) olan bir ton özelliğe sahip bir Order nesnem var. Şu anda bir Sipariş oluşturabilirim sorun değil, ancak yabancı anahtarı veya harici nesneleri ekleyemeden. MVC3 bunu hiçbir sorun oluşturmaz.

Nesneleri kaydetmeden önce denetleyici sınıfına kendim ekleyebileceğimin farkındayım, ancak kısıtlama ilişkileri karşılanmamışsa DbContext.SaveChanges () çağrısının başarısız olmasını istiyorum.

YENİ BİLGİ

Bu nedenle, özellikle, bir müşteri nesnesi belirtmeden bir Sipariş nesnesini kaydetmeye çalıştığımda bir istisna olmasını istiyorum. Nesneleri yalnızca Code First EF belgelerinin çoğunda açıklandığı gibi oluşturursam, bu davranış görünmüyor.

En son kod:

public class Order
{
    public int Id { get; set; }

    [ForeignKey( "Parent" )]
    public Patient Patient { get; set; }

    [ForeignKey("CertificationPeriod")]
    public CertificationPeriod CertificationPeriod { get; set; }

    [ForeignKey("Agency")]
    public Agency Agency { get; set; }

    [ForeignKey("Diagnosis")]
    public Diagnosis PrimaryDiagnosis { get; set; }

    [ForeignKey("OrderApprovalStatus")]
    public OrderApprovalStatus ApprovalStatus { get; set; }

    [ForeignKey("User")]
    public User User { get; set; }

    [ForeignKey("User")]
    public User Submitter { get; set; }

    public DateTime ApprovalDate { get; set; }
    public DateTime SubmittedDate { get; set; }
    public Boolean IsDeprecated { get; set; }
}

Bu, Hasta için VS tarafından oluşturulan görünüme erişirken şimdi aldığım hatadır:

HATA MESAJI

'PhysicianPortal.Models.Order' türündeki 'Hasta' özelliğindeki ForeignKeyAttribute geçerli değil. 'Parent' yabancı anahtar adı, bağımlı 'PhysicianPortal.Models.Order' türünde bulunamadı. Ad değeri, yabancı anahtar özellik adlarının virgülle ayrılmış bir listesi olmalıdır.

Saygılarımızla,

Guido

Yanıtlar:


164

Bir Ordersınıfınız varsa , modelinizdeki başka bir sınıfa başvuran bir özellik eklemek, örneğin CustomerEF'in orada bir ilişki olduğunu bilmesini sağlamak için yeterli olmalıdır:

public class Order
{
    public int ID { get; set; }

    // Some other properties

    // Foreign key to customer
    public virtual Customer Customer { get; set; }
}

İlişkiyi her zaman FKaçıkça ayarlayabilirsiniz :

public class Order
{
    public int ID { get; set; }

    // Some other properties

    // Foreign key to customer
    [ForeignKey("Customer")]
    public string CustomerID { get; set; }
    public virtual Customer Customer { get; set; }
}

ForeignKeyAttributeYapıcı bir parametre olarak bir dize alır: Bir yabancı anahtar özelliği üzerine koyun eğer ilişkili navigasyon özelliğin adını temsil eder. Gezinti özelliğine yerleştirirseniz, ilişkili yabancı anahtarın adını temsil eder.

Bunun anlamı şudur, mülkü nereye yerleştirirseniz ForeignKeyAttribute, Customerözellik CustomerIDyapıcıda yer alır:

public string CustomerID { get; set; }
[ForeignKey("CustomerID")]
public virtual Customer Customer { get; set; }

En Son Koda Göre DÜZENLE Bu hatayı şu satır nedeniyle alıyorsunuz:

[ForeignKey("Parent")]
public Patient Patient { get; set; }

EF, Parentonu Yabancı Anahtar uygulayıcısı olarak kullanmak için çağrılan bir özelliği arayacaktır . 2 şey yapabilirsiniz:

1) İlişkiyi gerektiği gibi işaretlemek için ForeignKeyAttributeonu çıkarın ve ile değiştirin RequiredAttribute:

[Required]
public virtual Patient Patient { get; set; }

Bir özelliği ile dekore etmenin RequiredAttributede güzel bir yan etkisi vardır: Veri tabanındaki ilişki ile oluşturulur ON DELETE CASCADE.

Ayrıca virtual, Lazy Loading'i etkinleştirmek için özelliği oluşturmanızı tavsiye ederim .

2) ParentYabancı Anahtar olarak hizmet verecek adlı bir özellik oluşturun . Bu durumda, örneğin onu çağırmak muhtemelen daha mantıklıdır ParentID(içindeki adı da değiştirmeniz gerekecektir ForeignKeyAttribute):

public int ParentID { get; set; }

Tecrübelerime göre bu durumda tam tersi olması daha iyi oluyor:

[ForeignKey("Patient")]
public int ParentID { get; set; }

public virtual Patient Patient { get; set; }

Teşekkürler Sergi - Blok alıntıya bazı ek bilgiler ekledim.
Guido Anselmi

@ Guido - Cevabımı en son kod düzenlemenize göre güncelledim, umarım bu yardımcı olur.
Sergi Papaseit

30

Yabancı anahtarı şu şekilde tanımlayabilirsiniz:

public class Parent
{
   public int Id { get; set; }
   public virtual ICollection<Child> Childs { get; set; }
}

public class Child
{
   public int Id { get; set; }
   // This will be recognized as FK by NavigationPropertyNameForeignKeyDiscoveryConvention
   public int ParentId { get; set; } 
   public virtual Parent Parent { get; set; }
}

Artık ParentId yabancı anahtar özelliğidir ve alt öğe ile mevcut üst öğe arasındaki gerekli ilişkiyi tanımlar. Çocuğu ebeveynden çıkmadan kurtarmak istisna oluşturacaktır.

FK mülk adınız navigasyon özelliği adı ve ana PK adından oluşmuyorsa, ilişkiyi eşlemek için ForeignKeyAttribute veri açıklamasını veya akıcı API'yi kullanmanız gerekir.

Veri açıklaması:

// The name of related navigation property
[ForeignKey("Parent")]
public int ParentId { get; set; }

Akıcı API:

modelBuilder.Entity<Child>()
            .HasRequired(c => c.Parent)
            .WithMany(p => p.Childs)
            .HasForeignKey(c => c.ParentId);

Diğer kısıtlama türleri, veri açıklamaları ve model doğrulaması ile uygulanabilir .

Düzenle:

Ayarlamazsanız bir istisna alırsınız ParentId. Bu gerekli özelliktir (null yapılamaz). Eğer bunu ayarlamazsanız, büyük olasılıkla veritabanına varsayılan değeri göndermeye çalışacaktır. Varsayılan değer 0'dır, dolayısıyla Id = 0 olan müşteriniz yoksa bir istisna alırsınız.


Teşekkürler Ladislav - Blok alıntıya bazı ek bilgiler ekledim.
Guido Anselmi

@Ladislav. Bu nedenle, bu kısıtlamayı uygulamak için hem Ebeveyn'e hem de ParentId'ye referansa sahip olmam GEREKİR. Bu doğru mu? Referans için yukarıdaki gerçek sınıfı ekleyeceğim.
Guido Anselmi

@ Guido: Yeni bilgi bu. Yabancı anahtar özelliklerini kullanmıyorsunuz. Tüm gezinme özellikleriniz varsayılan olarak isteğe bağlı olarak işlenir. Bunları gerektiği gibi eşlemek için akıcı haritalama kullanın.
Ladislav Mrnka

@Ladislav: Tekrar teşekkürler. Veri Ek Açıklamaları ile Fluent API kullanımı arasındaki farkları anlamak için etrafıma bakıyorum. Söylediğini düşündüğüm şey doğrultusunda yukarıdaki kodda değişiklikler yaptım. Yukarıdakilerin hepsi yapmam gereken mi? Saygılarımızla.
Guido Anselmi

Hiçbir ForeignKey özniteliği, yabancı anahtar özelliğiyle ilgili gezinme özelliğini tanımlamaz veya bunun tersi de geçerlidir. Yabancı anahtar özellikleriniz olmadığı için bu özelliği kullanamazsınız. Gezinme özelliklerinizde Gerekli özniteliği kullanmaya çalışın (test etmedim).
Ladislav Mrnka
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.