我是 MVC3 和 Web 开发的完整初学者。
我的客户端数据库使用一个表的唯一候选键作为另一个表的外键。我无法改变数据库的设计方式。我有从数据库表派生的模型。我知道实体框架不支持候选键作为另一个表的外键。
所以我的问题是,专业人士如何解决实体框架的这种限制?
我是 MVC3 和 Web 开发的完整初学者。
我的客户端数据库使用一个表的唯一候选键作为另一个表的外键。我无法改变数据库的设计方式。我有从数据库表派生的模型。我知道实体框架不支持候选键作为另一个表的外键。
所以我的问题是,专业人士如何解决实体框架的这种限制?
由于当前版本的 EF 要求 FK 指向 PK,这不是一个容易克服的问题。
我使用的一种技术是(使用 EF CodeFirst...er...Second)覆盖父表映射中的 PKEY 并指定匿名类型。
public class ParentObject
{
public int Id {get; set;} //the actual PKEY in the Db
public string CandidateKey1 {get;set;}
public string CandidateKey2 {get;set;}
public string CandidateKey3 {get;set;}
public virtual ICollection<ChildObject> ChildObjects {get;set;}
}
public class ChildObject
{
public int Id {get; set;}
public string CandidateKey1 {get;set;}
public string CandidateKey2 {get;set;}
public string CandidateKey3 {get;set;}
public virtual ParentObject ParentObject {get;set;}
}
为了使它工作,您需要指定 Parent 表的 PKEY 是一个匿名对象,而不是实际存储在 DB 中的 PKEY。
public ParentObjectMap()
{
// Primary Key
//this.HasKey(t => t.Id); //override this as PKEY for EF purposes
this.HasKey(t => new { t.CandidateKey1, t.CandidateKey2, t.CandidateKey3 });
// Table & Column Mappings
this.ToTable("ParentTable");
this.Property(t => t.Id).HasColumnName("ParentId");
this.Property(t => t.CandidateKey1).HasColumnName("Key1");
this.Property(t => t.CandidateKey2).HasColumnName("Key2");
this.Property(t => t.CandidateKey3).HasColumnName("Key3");
}
和子对象图
public ChildObjectMap()
{
// Primary Key
this.HasKey(t => t.Id);
// Table & Column Mappings
this.ToTable("ChildTable");
this.Property(t => t.Id).HasColumnName("ChildId");
this.Property(t => t.CandidateKey1).HasColumnName("Key1");
this.Property(t => t.CandidateKey2).HasColumnName("Key2");
this.Property(t => t.CandidateKey3).HasColumnName("Key3");
this.HasRequired(t => t.ParentObject)
.WithMany(t => t.ChildObjects)
.HasForeignKey(t => new { t.CandidateKey1, t.CandidateKey2, t.CandidateKey3 });
}
当然,这会引入其他问题,例如您需要在实现的代码中处理的实际 Parent Id 属性的唯一性。但是,当针对类似(候选键控)Progress 4GL OpenEdge -> MSSQL db 编写代码时,这种技术已经为我完成了工作,而我无法控制。
它也没有本地 EF -> MSSQL 映射快,后者利用了数据库中的 FK 关系。