如何在MVC3中使用Code First Entity Framework(4.1)声明外键关系?

时间:2011-04-04 18:47:41

标签: asp.net-mvc-3 ef-code-first entity-framework-4.1

我一直在寻找有关如何使用代码首先使用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'。该   名称值应以逗号分隔   外键属性名称列表。

此致

2 个答案:

答案 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的客户,您将获得例外。