我正在尝试创建一个 EF6 数据库,其中两个表“地址”和“访问”共享与主键相同的值。从概念上讲,访问是地址的扩展。我拆分表是因为地址中的大多数记录不需要访问中包含的字段。
我正在使用代码优先的方法。这是地址的相关代码:
public class Address
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ID { get; set; }
[ForeignKey( "ID" )]
public virtual Visit Visit { get; set; }
访问:
public class Visit
{
[Key]
[DatabaseGenerated( DatabaseGeneratedOption.Identity )]
public int ID { get; set; }
[ForeignKey("ID")]
public virtual Address Address { get; set; }
根据我的研究,我还需要在数据上下文的 OnModelCreating 方法中包含以下内容:
modelBuilder.Entity<Visit>()
.HasOptional( v => v.Address )
.WithRequired();
不幸的是,这不起作用。在消除从地址中删除主索引的脚手架调用之后,我可以更新数据库(可能是因为添加迁移代码认为主键“仅仅是”外键字段)。但是当我运行该应用程序时,出现以下错误:
列名“Address_ID”无效。 列名称“Address_ID”无效。
根据我对 EF6 的有限经验,这看起来像是框架深处的某个地方,它期望有名为“Address_ID”的字段,可能在“访问”表中(基于我见过的“表名称”_“字段名称”命名结构)对于其他隐式添加的字段)。
我想做的事情可能吗?如果是这样,我的配置中缺少什么?
附加信息
在尝试 bubi 提出的解决方案时,不幸的是仍然生成相同的错误,我可以消除 OnModelCreating 代码,但仍然生成功能迁移代码。
分辨率
我终于做了我之前应该做的事情,即检查由正在崩溃的查询生成的实际 T-SQL 代码。事实证明,问题不在于访问/地址链接,而在于涉及另一个表的完全独立的关系。显然,在这个过程中我做了一些事情让 EF 认为其他表(Voters)有一个 Address_ID 外键字段。实际上,地址/投票者关系应该并且最初是与 Voter.AddressID 字段绑定的。
我没有尝试解除大量迁移,而是选择放弃数据库、放弃迁移并从头开始。重新创建数据库后——但使用布比的建议——我从备份中重新加载了数据,瞧,我又开始工作了。
为了完整起见,以下是我最终必须放入 OnModelCreating 方法调用中以使地址/访问关系正常工作的代码:
modelBuilder.Entity<Visit>()
.HasRequired( v => v.Address )
.WithRequiredDependent( a => a.Visit );
modelBuilder.Entity<Address>()
.HasRequired( a => a.Visit )
.WithRequiredPrincipal( v => v.Address );
我有点困惑为什么我必须使用 HasRequired 才能使用 WithRequiredPrincipal/WithRequiredDependent,因为并非地址表中的每个条目在访问表中都有一个条目。这似乎是“可选的”,而不是“必需的”。但它似乎有效,也许“必需”部分只是 EF 数据库模型的内部,而不是数据库本身。
模型中有2个问题:
- 只有其中一个键可以自动编号,另一个必须获得相同的 Id(这由 EF 独立)。
- 映射问题。
这个模型应该可以工作。
public class Address
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string Description { get; set; }
public virtual Visit Visit { get; set; }
}
public class Visit
{
public Visit()
{
Address = new Address();
}
[Key]
[ForeignKey("Address")]
public int Id { get; set; }
public string Description { get; set; }
public virtual Address Address { get; set; }
}
使用示例
var visit = new Visit
{
Description = "Visit",
Address = {Description = "AddressDescription"}
};
db.Visits.Add(visit);
db.SaveChanges();
除了 bubi 提到的内容之外,您的
modelBuilder
陈述与模型相矛盾,因为它没有提到 Address.Visit
作为逆属性。因此它认为该属性代表一个单独的关系,并尝试为该关系创建 Address_ID
列。
你需要有
modelBuilder.Entity<Visit>()
// from your description sounds like every Visit needs an Address
.HasRequired(v => v.Address )
// need to mention the inverse property here if you have one
.WithOptional(a => a.Visit);
...或者完全删除该语句,因为您已经在使用属性,并且 EF 应该能够按照约定找出它。