EF6 代码第一个多个一对多映射问题/"Multiplicity" 错误

EF6 code first multiple 1-to-many mapping issue / "Multiplicity" error

我在尝试创建数据库时收到以下错误消息:

One or more validation errors were detected during model generation:

Interaction_CauseElement_Source: : Multiplicity is not valid in Role 'Interaction_CauseElement_Source' in relationship 'Interaction_CauseElement'. Because the Dependent Role properties are not the key properties, the upper bound of the multiplicity of the Dependent Role must be '*'.

Interaction_EffectElement_Source: : Multiplicity is not valid in Role 'Interaction_EffectElement_Source' in relationship 'Interaction_EffectElement'. Because the Dependent Role properties are not the key properties, the upper bound of the multiplicity of the Dependent Role must be '*'.

我在其他 Stack Overflow 帖子中看到过这个错误,但在我发现的示例中,OP 试图在 table 之间的两个方向上建立一对一的关系。那不是我要找的。

这是我的模型:

public class Element
{
    [Key]
    public int ID { get; set; }

    [Required, MaxLength(64)]
    public string Name { get; set; }

    [MaxLength(200)]
    public string Description { get; set; }
}

public class Interaction
{
    [Key]
    public int ID { get; set; }

    [Index, Required]
    public int CauseID { get; set; }

    [Index, Required]
    public int EffectID { get; set; }

    [MaxLength(64)]
    public string Location { get; set; }    

    [ForeignKey("CauseID")]
    public virtual Element CauseElement { get; set; }

    [ForeignKey("EffectID")]
    public virtual Element EffectElement { get; set; }
}

元素 table 中的项目是独一无二的。一对元素可以在任意数量的位置相互作用。 CauseID/EffectID 对不会是唯一的。

我要更改模型的唯一其他地方是 OnModelCreating 方法。我收到了这个错误:

Introducing FOREIGN KEY constraint 'FK_dbo.Interactions_dbo.Elements_Cause' on table 'Interactions' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints. Could not create constraint. See previous errors.

并且必须为模型创建级联策略。此代码修复了该错误:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    //Prevent cyclic cascade on elements table
    modelBuilder.Entity<Interaction>()
        .HasRequired(i => i.CauseElement)
        .WithRequiredDependent()
        .WillCascadeOnDelete(false);
    modelBuilder.Entity<Interaction>()
        .HasRequired(i => i.EffectElement)
        .WithRequiredDependent()
        .WillCascadeOnDelete(false);

    base.OnModelCreating(modelBuilder);
}

但后来我收到了神秘的 "Multiplicity" 错误。它似乎希望我将 public virtual Element CauseElement 变成一个像 public virtual ICollection<Element> CauseElement 这样的集合,但这并不能正确地建立关系模型。

您推翻了 "ForeignKey" 属性的职责。它继续 ID 字段,指定 属性 作为外键。您想要如下内容:

// To-One on Element 
[ForeignKey("Element")]
public int ElementId { get; set; }
public virtual Element Element { get; set; }

另外,这其实是一对一的关系。在这种情况下,一对多关系是:

// To-Many on Element 
public virtual ICollection<Element> Elements{ get; set; }

我找到了解决办法。 This article on EntityFrameworkTutoral.net helped out. 因为我需要从 Interaction class 到 Element class 的两个引用,这种关系太复杂了,无法在 EF 中仅使用属性进行建模。

我不得不更新模型,然后使用流利的 API 告诉 EF 如何处理关系。我将模型更新为以下内容:

public class Element
{
    public Element()
    {
        CauseElements = new List<Interaction>();
        EffectElements = new List<Interaction>();
    }

    [Key]
    public int ID { get; set; }

    [Required, MaxLength(64)]
    public string Name { get; set; }

    #region Navigation

    public virtual ICollection<Interaction> CauseElements { get; set; }
    public virtual ICollection<Interaction> EffectElements { get; set; }

    #endregion
}

public class Interaction
{
    [Key]
    public int ID { get; set; }

    [Index]
    public int CauseID { get; set; }

    [Index]
    public int EffectID { get; set; }

    [MaxLength(64)]
    public string Location { get; set; }

    #region Navigation

    [ForeignKey("CauseID")]
    public virtual Element CauseElement { get; set; }

    [ForeignKey("EffectID")]
    public virtual Element EffectElement { get; set; }

    #endregion
}

在我的 DbContext class 中,我使用流畅的 API 在 Interaction.CauseElementElement.CauseElements 之间创建了 link 并且 属性 是 Interaction table 的外键(与 Effect 关系相同):

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    //Prevent cyclic cascade on elements table
    modelBuilder.Entity<Interaction>()
        .HasRequired(i => i.CauseElement)
        .WithRequiredDependent()
        .WillCascadeOnDelete(false);
    modelBuilder.Entity<Interaction>()
        .HasRequired(i => i.EffectElement)
        .WithRequiredDependent()
        .WillCascadeOnDelete(false);

    //Create the links between the element, the key, and the collection
    modelBuilder.Entity<Interaction>()
        .HasRequired<Element>(i => i.CauseElement)
        .WithMany(e => e.CauseElements)
        .HasForeignKey(i => i.CauseID);
    modelBuilder.Entity<Interaction>()
        .HasRequired<Element>(i => i.EffectElement)
        .WithMany(e => e.EffectElements)
        .HasForeignKey(i => i.EffectID);

    base.OnModelCreating(modelBuilder);
}

当你有一个简单的一对多关系时,Entity Framework 似乎试图自动推断 table 之间的关系。如果我从 Interaction class 中删除了 EffectElement(并且从 Element 中删除了 EffectElements),EF 能够轻松创建关系。但是当我把它加回去的时候,我又收到了错误。

由于 Element 类型在 Interaction class 中出现了两次,它不知道如何创建关系。我必须在 OnModelCreating 方法中明确定义它。