Как я должен объявить отношения внешнего ключа, используя Code First Entity Framework (4.1) в MVC3?


Я искал ресурсы о том, как объявить отношения внешнего ключа и другие ограничения с помощью кода first EF 4.1 без особого успеха. В основном я строю модель данных в коде и использую MVC3 для запроса этой модели. Все работает через MVC, что отлично (слава Microsoft!) но теперь я хочу, чтобы он не работал, потому что мне нужно иметь ограничения модели данных.

например, у меня есть объект Order, который имеет массу свойств, которые являются внешними объектами (таблицами). Сейчас я могу создать заказ без проблем, но без возможности добавить внешний ключ или внешние объекты. MVC3 устанавливает это без проблем.

Я понимаю, что я мог бы просто добавить объекты сам в класс контроллера до сохранения, но я хотел бы вызвать DbContext.SaveChanges () для сбоя, если отношения ограничений не были выполнены.

НОВАЯ ИНФОРМАЦИЯ

Так, в частности, я хотел бы исключение, возникающее при попытке к сохранение объекта заказа без указание объекта клиента. Этот не похоже на поведение, если я просто составьте объекты, как описано в большинстве документов Code First EF.

последний код:

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

это ошибка, которую я получаю сейчас при доступе к VS сгенерированное представление для пациента:

СООБЩЕНИЕ ОБ ОШИБКЕ

атрибут ForeignKeyAttribute в свойстве "Пациент" по типу - Медицинский портал.Модели.Тем не действительный. Имя внешнего ключа 'Parent' не найден зависимый тип - Медицинский портал.Модели.Порядок'. Этот Значение имени должно быть разделено запятой список имен свойств внешнего ключа.

С уважением,

Guido

2 90

2 ответа:

если у вас Order класс, добавление свойства, которое ссылается на другой класс В вашей модели, например Customer должно быть достаточно, чтобы EF знал, что там есть связь:

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

    // Some other properties

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

вы всегда можете установить FK связи в явном виде:

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

The ForeignKeyAttribute конструктор принимает строку в качестве параметра: если вы помещаете ее в свойство внешнего ключа, она представляет имя связанного свойства навигации. Если вы поместите его на навигацию свойство представляет собой имя связанного внешнего ключа.

что это значит, если вы где разместить ForeignKeyAttribute на Customer свойство, атрибут будет взять CustomerID в конструкторе:

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

редактировать на основе Код Вы получаете эту ошибку из-за этой строки:

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

EF будет искать свойство под названием Parent использовать его в качестве внешнего ключа enforcer. Вы можете сделать 2 вещи:

1) удалить ForeignKeyAttribute и заменить на RequiredAttribute чтобы отметить отношение по мере необходимости:

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

украшать свойство с RequiredAttribute также имеет приятный побочный эффект: связь в базе данных создается с помощью ON DELETE CASCADE.

я бы также рекомендовал сделать свойство virtual для включения отложенной загрузки.

2) Создайте свойство под названием Parent что будет служить в качестве внешнего ключа. В этом случае он, вероятно, делает больше смысл назвать его например ParentID (вам нужно будет изменить имя в ForeignKeyAttribute так же):

public int ParentID { get; set; }

по моему опыту в этом случае, хотя это работает лучше наоборот:

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

public virtual Patient Patient { get; set; }

вы можете определить внешний ключ на:

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

теперь ParentId является свойством внешнего ключа и определяет необходимое отношение между дочерним и существующим родителем. Сохранение ребенка без выхода родителя вызовет исключение.

если ваше имя свойства FK не состоит из имени свойства навигации и родительского имени PK, вы должны использовать аннотацию данных ForeignKeyAttribute или fluent API для сопоставления отношения

сведения аннотация:

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

Fluent API:

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

другие типы ограничений могут быть применены с помощью аннотации данных и проверка модели.

Edit:

вы получите исключение, если вы не установите ParentId. Это обязательное свойство (не обнуляется). Если вы просто не установите его, он, скорее всего, попытается отправить значение по умолчанию в базу данных. Значение по умолчанию-0, поэтому если у вас нет клиента с id = 0 вы получите исключение.