Roberto Durand
Roberto Durand

Reputation: 137

Trouble configuring many to many relationship in Entity Framework

I'm trying to replicate a M-M relationship from a Database with code first EF6 but had no luck. I have tried some tutorial links and some answers from here but still get the same error.

This is just a few things i have tried out:
https://learn.microsoft.com/en-us/aspnet/mvc/overview/getting-started/getting-started-with-ef-using-mvc/creating-an-entity-framework-data-model-for-an-asp-net-mvc-application
http://www.entityframeworktutorial.net/code-first/configure-many-to-many-relationship-in-code-first.aspx
relationship problems in EF code-first

Error: The entity types 'AdjustmentType' and 'AdjustmentReason' cannot share table 'AdjustmentReason' because they are not in the same type hierarchy or do not have a valid one to one foreign key relationship with matching primary keys between them.

Thanks!

enter image description here

[Serializable]
[Table("schema.AdjustmentReason")]
public class AdjustmentType : AuditableEntity
{
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int AdjustmentTypeId { get; set; }

    [Column("AdjustmentType")]
    [StringLength(50)]
    public string AdjustmentType1 { get; set; }

    public virtual ICollection<AdjustmentReasonType> AdjustmentReasonType { get; set; }
}

[Serializable]
[Table("schema.AdjustmentReason")]
public class AdjustmentReason : AuditableEntity
{
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int AdjustmentReasonId { get; set; }

    [Column("AdjustmentReason")]
    [StringLength(50)]
    public string AdjustmentReason1 { get; set; }

    public bool? Hidden { get; set; }

    public ICollection<Transaction> Transactions { get; set; }
    public virtual ICollection<AdjustmentReasonType> AdjustmentReasonType { get; set; }      
}

public class AdjustmentReasonType : AuditableEntity
{
    public int AdjustmentReasonTypeId { get; set; }

    public int AdjustmentReasonId { get; set; } //This is required

    public int AdjustmentTypeId { get; set; } //This is optional

    public virtual AdjustmentType AdjustmentType { get; set; }

    public virtual AdjustmentReason AdjustmentReason { get; set; }

}

//DatabaseContext.cs
        modelBuilder.Entity<AdjustmentReason>()
            .HasMany(e => e.AdjustmentReasonTypes)
            .WithRequired(e => e.AdjustmentReason);
        modelBuilder.Entity<AdjustmentType>()
            .HasMany(e => e.AdjustmentReasonType)
            .WithRequired(e => e.AdjustmentType);
//IDatabaseContext.cs
        IDbSet<AdjustmentReason> AdjustmentReasons { get; set; }

        IDbSet<AdjustmentType> AdjustmentTypes { get; set; }

        IDbSet<AdjustmentReasonType> AdjustmentReasonTypes { get; set; }

Upvotes: 0

Views: 120

Answers (2)

Roberto Durand
Roberto Durand

Reputation: 137

Found the solution to the error!
Turned out that I named both the AdjustmentReason and AdjustmenType as "Schema.AdjustmentReason" in the data annotation of the class. I have updated the code in the question area to show the data annotations errors I had in both classes.

Before:

[Serializable]
[Table("schema.AdjustmentReason")]
public class AdjustmentType : AuditableEntity

[Serializable]
[Table("schema.AdjustmentReason")]
public class AdjustmentReason : AuditableEntity

After:

[Serializable]
[Table("schema.AdjustmentType")]
public class AdjustmentType : AuditableEntity

[Serializable]
[Table("schema.AdjustmentReason")]
public class AdjustmentReason : AuditableEntity

This is the link that helped me realized what I had done wrong: http://geekswithblogs.net/tonyt/archive/2013/07/02/153327.aspx

I apologize for not putting the data annotations before, I did not think that it was needed, for that I'm sorry.

Thanks!

Upvotes: 0

Steve Py
Steve Py

Reputation: 34773

A couple of alterations that may help...

public class AdjustmentType : AuditableEntity
{ //Good...
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int AdjustmentTypeId { get; set; }

    [Column("AdjustmentType")]
    [StringLength(50)]
    public string AdjustmentType1 { get; set; }

    public virtual ICollection<AdjustmentReasonType> AdjustmentReasonType { get; set; }
}

public class AdjustmentReason : AuditableEntity
{ //Good...
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int AdjustmentReasonId { get; set; }

    [Column("AdjustmentReason")]
    [StringLength(50)]
    public string AdjustmentReason1 { get; set; }

    public bool? Hidden { get; set; }

    public ICollection<Transaction> Transactions { get; set; }
    public virtual ICollection<AdjustmentReasonType> AdjustmentReasonType { get; set; }      
}

public class AdjustmentReasonType : AuditableEntity
{ // Remove the FKs...
    public int AdjustmentReasonTypeId { get; set; }

    //public int AdjustmentReasonId { get; set; } //This is required

    //public int AdjustmentTypeId { get; set; } //This is optional

    public virtual AdjustmentType AdjustmentType { get; set; }

    public virtual AdjustmentReason AdjustmentReason { get; set; }

}

//DatabaseContext.cs
// Add the FK declarations here so that EF knows how to resolve these back to the parent references.

        modelBuilder.Entity<AdjustmentReason>()
            .HasMany(e => e.AdjustmentReasonTypes)
            .WithRequired(e => e.AdjustmentReason)
            .Map(e=> e.MapKey("AdjustmentReasonId"); // FK column name.
        modelBuilder.Entity<AdjustmentType>()
            .HasMany(e => e.AdjustmentReasonType)
            .WithRequired(e => e.AdjustmentType)
            .Map(e=> e.MapKey("AdjustmentTypeId");

//IDatabaseContext.cs
        IDbSet<AdjustmentReason> AdjustmentReasons { get; set; }

        IDbSet<AdjustmentType> AdjustmentTypes { get; set; }
        // Remove these, typically you would be dealing with Reasons or Types, not the linking table directly. Use the references
        //IDbSet<AdjustmentReasonType> AdjustmentReasonTypes { get; set; }

Upvotes: 1

Related Questions