【问题标题】:EF table splitting: InvalidOperationException - sequence contains more than one matching elementEF 表拆分:InvalidOperationException - 序列包含多个匹配元素
【发布时间】:2012-11-03 02:15:32
【问题描述】:

我有一个我认为可能是 EF 错误的重现。我想将一张表拆分为两个实体。这些实体中的每一个都包含对第三实体的引用。这两个引用必须使用相同的外键属性名称公开。由于它们映射到同一个表中的列,因此使用配置(或在此示例中为属性)来使列名唯一。

当我尝试加载模型时,我从 EF 收到上述异常。如果我修改了 FK 属性之一的名称,那么错误就会消失。

这是我的模型。代码按原样工作。要重现此问题,请将 Foo2.Foo3Id1 重命名为 Foo3Id,这是我需要它具有的值。

您为什么要这样做?

如果您想知道为什么我需要两个属性具有相同的名称,这里是解释。

我有一个包含多个地址(例如邮政地址和帐单地址)的表格。这是一个现有的数据库,所以我无法更改表结构。每个地址由一系列标准列表示。每列的名称都有一个前缀标识地址的种类和一个后缀标识地址的一部分,例如。 BillingAddressLine1BillingAddressZipCodePostalAddressLine1

似乎使用复杂类型可以解决这个问题。但是,还有一个复杂的问题:每个地址都包含一个引用Cities 表的CityId。复杂类型don't support relationships and navigation properties。所以我打算的解决方案是改用表拆分,并将每组地址属性拆分为自己的实体。每个表示地址的实体要么派生自一个基本类型,比如Address,要么实现一个接口,IAddress

通过表拆分,我仔细观察了多个类型映射到同一个表的限制,they must all have navigation properties to each other

在下面的代码中,Foo1Foo2 都是地址类型(并且会实现一些通用接口)。 Foo3City。这是我能想到的最简单的问题重现。

代码示例

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 限制吗?

【问题讨论】:

  • 你能在entityframework.codeplex.com上报告这个吗?我不知道这是否受支持,但如果不支持,那么你应该得到一个更好的例外
  • @Pawel - 谢谢。我创建了entityframework.codeplex.com/workitem/643 并在此处添加了更多信息,说明我为什么要这样做。如果没有这些背景信息,这听起来有点晦涩。
  • Brice 找到了一种解决方法,您可以在修复之前一直使用它——他将其发布在 codeplex 网站上。以防万一:“在解决此问题之前,更改其中一个属性名称是一种有效的解决方法。”
  • @Pawel - 谢谢,虽然我确实在我的场景中解释过,“这两个引用 必须 使用相同的外键属性名称公开。”看起来我只是不能做我现在想做的事。

标签: entity-framework ef-code-first poco .net-4.5


【解决方案1】:

这确实是一个错误,现在已经修复。见http://entityframework.codeplex.com/workitem/643

【讨论】:

  • 那是在 6.0.0.我的链接大约是 6.1.0,可能会重新引入它。但现在似乎已修复(?)
【解决方案2】:

该错误在 6.0 中仍然存在。看看这里:https://entityframework.codeplex.com/workitem/546 + 另一个相关的错误:https://entityframework.codeplex.com/workitem/2116

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-02-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-19
    • 2015-09-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多