Как я должен объявить отношения внешнего ключа, используя 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 ответа:
если у вас
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 вы получите исключение.