我一直在寻找有关如何使用代码首先使用EF 4.1声明外键关系和其他约束的资源,而没有太多运气。基本上我是在代码中构建数据模型并使用MVC3来查询该模型。一切都通过MVC工作,这是伟大的(对微软的赞誉!)但现在我希望它不工作,因为我需要有数据模型约束。
例如,我有一个Order对象,它有很多属性是外部对象(表)。现在我可以创建一个没有问题的订单,但是无法添加外键或外部对象。 MVC3设置这没问题。
我意识到我可以在保存之前在控制器类中自己添加对象,但如果未满足约束关系,我希望调用DbContext.SaveChanges()失败。
新信息
所以,具体来说,我想要一个 我尝试时会发生异常 保存Order对象而不用 指定客户对象。这个 如果我,似乎不是这种行为 只是按照描述组合对象 在大多数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 类型'患者' 'PhysicianPortal.Models.Order'不是 有效。外键名称'Parent' 在依赖类型上找不到 'PhysicianPortal.Models.Order'。该 名称值应以逗号分隔 外键属性名称列表。
此致
圭
答案 0 :(得分:152)
如果你有一个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; }
}
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
的属性,以将其用作外键实施器。你可以做两件事:
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; }
答案 1 :(得分:28)
您可以通过以下方式定义外键:
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);
其他类型的约束可以由data annotations and model validation强制执行。
编辑:
如果您未设置ParentId
,则会收到异常。它是必需的属性(不可为空)。如果您只是不设置它,它很可能会尝试将默认值发送到数据库。默认值为0,因此如果您没有Id = 0的客户,您将获得例外。