如何使用 MVC3中的代码优先实体框架(4.1)声明外键关系?

我一直在搜索关于如何使用第一代码 EF 4.1声明外键关系和其他约束的资源,但没有多少运气。基本上,我是在代码中构建数据模型,并使用 MVC3查询该模型。一切都通过 MVC 工作,这是伟大的(赞美微软!)但是现在我希望它不工作,因为我需要有数据模型的约束。

例如,我有一个 Order 对象,它有大量属性是外部对象(表)。现在我可以创建一个 Order 没有问题,但是不能添加外键或外部对象。MVC3设置这个没有问题。

我意识到我可以在保存之前自己在控制器类中添加对象,但是我希望调用 DbContext。如果未满足约束关系,则 SaveChanges ()将失败。

最新消息

所以,具体来说,我想要一个 当我试图 保存 Order 对象 指定客户对象 似乎不是行为,如果我 只要按照所描述的对象进行组合 在大多数代码优先 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 生成的 Patientview 时得到的错误:

错误信息

属性的 ForeignKeyAttribute “病人”的类型 “医生入口,模型,秩序”不是 有效。外键名“ Parent” 在依赖类型上没有发现 “医生入口。模型。秩序” 名称值应以逗号分隔 外键属性名列表。

问候,

圭多

181947 次浏览

If you have an Order class, adding a property that references another class in your model, for instance Customer should be enough to let EF know there's a relationship in there:

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


// Some other properties


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

You can always set the FK relation explicitly:

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 constructor takes a string as a parameter: if you place it on a foreign key property it represents the name of the associated navigation property. If you place it on the navigation property it represents the name of the associated foreign key.

What this means is, if you where to place the ForeignKeyAttribute on the Customer property, the attribute would take CustomerID in the constructor:

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

EDIT based on Latest Code You get that error because of this line:

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

EF will look for a property called Parent to use it as the Foreign Key enforcer. You can do 2 things:

1) Remove the ForeignKeyAttribute and replace it with the RequiredAttribute to mark the relation as required:

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

Decorating a property with the RequiredAttribute also has a nice side effect: The relation in the database is created with ON DELETE CASCADE.

I would also recommend making the property virtual to enable Lazy Loading.

2) Create a property called Parent that will serve as a Foreign Key. In that case it probably makes more sense to call it for instance ParentID (you'll need to change the name in the ForeignKeyAttribute as well):

public int ParentID { get; set; }

In my experience in this case though it works better to have it the other way around:

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


public virtual Patient Patient { get; set; }

You can define foreign key by:

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

Now ParentId is foreign key property and defines required relation between child and existing parent. Saving the child without exsiting parent will throw exception.

If your FK property name doesn't consists of the navigation property name and parent PK name you must either use ForeignKeyAttribute data annotation or fluent API to map the relation

Data annotation:

// 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);

Other types of constraints can be enforced by data annotations and model validation.

Edit:

You will get an exception if you don't set ParentId. It is required property (not nullable). If you just don't set it it will most probably try to send default value to the database. Default value is 0 so if you don't have customer with Id = 0 you will get an exception.