我一直在寻找有关如何使用代码优先 EF 4.1 声明外键关系和其他约束的资源,但运气不佳。基本上我在代码中构建数据模型并使用 MVC3 来查询该模型。一切都通过 MVC 工作,这很棒(向微软致敬!)但现在我不希望它工作,因为我需要有数据模型约束。
例如,我有一个 Order 对象,它有大量的外部对象(表)属性。现在我可以创建一个 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 生成的 Patient 视图时遇到的错误:
错误消息“PhysicianPortal.Models.Order”类型的属性“Patient”上的 ForeignKeyAttribute 无效。在依赖类型“PhysicianPortal.Models.Order”上找不到外键名称“Parent”。 Name 值应该是逗号分隔的外键属性名称列表。
问候,
圭多
如果您有一个 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; }
EDIT based on Latest Code 由于这一行,您会收到该错误:
[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; }
您可以通过以下方式定义外键:
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 数据注释或流式 API 来映射关系
数据注释:
// The name of related navigation property
[ForeignKey("Parent")]
public int ParentId { get; set; }
流畅的 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 的客户,您将收到异常。