我有一个我认为可能是 EF 错误的重现。我想将一张表拆分为两个实体。这些实体中的每一个都包含对第三实体的引用。这两个引用必须使用相同的外键属性名称公开。由于它们映射到同一个表中的列,因此使用配置(或在此示例中为属性)来使列名唯一。
当我尝试加载模型时,我从 EF 获得了上述异常。如果我修改 FK 属性之一的名称,那么错误就会消失。
这是我的模型。代码按原样工作。要重现该问题,请重命名Foo2.Foo3Id1
为Foo3Id
,这是我需要它具有的值。
你为什么想这么做?
如果您想知道为什么我需要这两个属性具有相同的名称,这里是解释。
我有一个包含多个地址的表(例如邮政地址和帐单地址)。这是一个现有的数据库,所以我无法更改表结构。每个地址由一系列标准列表示。每列的名称都有一个前缀标识地址的种类和一个后缀标识地址的一部分,例如BillingAddressLine1
,BillingAddressZipCode
和PostalAddressLine1
。
似乎使用复杂类型可以解决这个问题。但是,还有一个复杂的问题:每个地址都包含一个CityId
引用Cities
表的地址。复杂类型不支持关系和导航属性。所以我打算的解决方案是改用表拆分,并将每组地址属性拆分为自己的实体。每个表示地址的实体要么派生自基类型,例如,Address
要么实现接口IAddress
。
使用表格拆分时,我仔细观察了多个类型映射到同一个表格的限制,它们必须都具有彼此的导航属性。
在下面的代码中,Foo1
andFoo2
都是地址类型(并且会实现一些通用接口)。 Foo3
是City
。这是我能想到的最简单的问题重现。
代码示例
class Program
{
static void Main(string[] args)
{
// Use NuGet to import EF 5 into the project.
// This code is just enough to cause the metadata to be loaded and therefore demo the error.
using (Context cx = new Context())
{
var qq = from f in cx.Foo3s
where f.Foo1s.Any()
select f;
}
}
}
[Table("Foo")]
public class Foo1
{
[Key]
public virtual int Id { get; set; }
[Required]
public virtual Foo2 Foo2 { get; set; }
[ForeignKey("Foo3")]
[Column("Foo1_Foo3Id")]
public virtual int? Foo3Id { get; set; }
public virtual Foo3 Foo3 { get; set; }
}
[Table("Foo")]
public class Foo2
{
[Key]
public virtual int Id { get; set; }
[Required]
public virtual Foo1 Foo1 { get; set; }
// Re-name the following property to Foo3Id (rather than Foo3Id1) and the model won't load.
// You get "InvalidOperationException: Sequence contains more than one matching element."
[ForeignKey("Foo3")]
[Column("Foo2_Foo3Id")]
public virtual int? Foo3Id1 { get; set; }
public virtual Foo3 Foo3 { get; set; }
}
[Table("Foo3")]
public class Foo3
{
[Key]
public virtual int Id { get; set; }
[InverseProperty("Foo3")]
public virtual ICollection<Foo1> Foo1s { get; set; }
[InverseProperty("Foo3")]
public virtual ICollection<Foo2> Foo2s { get; set; }
}
public class Context : DbContext
{
public DbSet<Foo3> Foo3s { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
// Don't think we can configure 1:1 relationship using just attributes.
var foo2 = modelBuilder.Entity<Foo2>();
foo2.HasRequired(q => q.Foo1)
.WithRequiredPrincipal(q => q.Foo2);
}
}
这是一个错误吗?难道我做错了什么?这是一个已知的 EF 限制吗?