EF6 Code: First Multiple 1-to-Many Mapping Error / Multiple Error

I am getting the following error when trying to create a database:

One or more validation errors were encountered during model generation:

Interaction_CauseElement_Source :: multiplicity is not valid in role "Interaction_CauseElement_Source" in relationship 'Interaction_CauseElement. Since the properties of the dependent role and not the key properties, the upper bound for the cardinality of the dependent role must be "*".

Interaction_EffectElement_Source :: multiplicity is not valid in role "Interaction_EffectElement_Source" in relationship 'Interaction_EffectElement. Since the properties of the dependent role and not the key properties, the upper bound for the cardinality of the dependent role must be "*".

I've seen this error in other posts, but in the examples I found the OP was trying to establish a 1 to 1 relationship in both directions between tables. This is not what I am looking for.

Here is my model:

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; }
}

      

Elements in the Elements table are unique. A pair of elements can interact with each other in any number of locations. The CauseID / EffectID pair will not be unique.

The only other place where I change the model is in the method OnModelCreating

. I got this error:

The FOREIGN KEY constraint view 'FK_dbo.Interactions_dbo.Elements_Cause' in the Interactions table can cause loops or multiple cascading paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or change other FOREIGN KEY Constraints. Failed to create constraint. See previous errors.

And it was necessary to create a cascading policy for the model. This code fixed this error:

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);
}

      

But then I got the cryptic "Plurality" error. It looks like he wants me to do public virtual Element CauseElement

in the collection sort of public virtual ICollection<Element> CauseElement

, but that might not model the relationship correctly.

+3


source to share


2 answers


I found a solution. This article on EntityFrameworkTutoral.net helped. Since I need two references from class Interaction

to class Element

, this relationship is also tricky to model in EF with only attributes.

I had to update the model and then use the fluent API to tell EF how to treat relationships. I have updated my model to the following:

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
}

      

And in my DbContext class, I used a fluent API to create a relationship between Interaction.CauseElement

and Element.CauseElements

and which property was a foreign key to the table Interaction

(and same with the Effect relationship):



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);
}

      

It seems that the Entity Framework is trying to automatically infer the relationships between tables when you have a simple one-to-many relationship. If I removed EffectElement

from the class Interaction

(and EffectElements

from Element

), EF was able to create the relationship easily. But when I added it back, I got the error again.

Since the type Element

appeared twice in the class Interaction

, he didn't know how to create a relationship. I had to explicitly define it in the method OnModelCreating

.

+1


source


You have removed the responsibility of the "ForeignKey" attribute. It goes into an identifier field, indicating the property for which it serves as a foreign key. You want something like below:

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

      



Also, it's actually a one-to-one relationship. The one-to-many relationship in this case would be:

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

      

0


source







All Articles