How to fix: The number of properties in the Dependent and Principal Roles in a relationship constraint must be identical?

36,172

Solution 1

The reason for the error are incorrectly configured relations in your model. This is not correct:

    one.HasRequired(t => t.Two)
        .WithMany(s => s.Ones)
        .HasForeignKey(t => t.TwoId);

    one.HasRequired(t => t.Three)
        .WithMany(s => s.Ones)
        .HasForeignKey(t => t.ThreeId);

It should be:

    one.HasRequired(t => t.Two)
        .WithMany(s => s.Ones)
        .HasForeignKey(t => new { t.TwoId, t.ThreeId });

Because dependent's FK must contain all columns of principal PK. You must also remove navigation property from Three to One.

Solution 2

This can also be caused by Code first from Database.

I had several views that I brought in that did not have an obvious key field according to Entity Framework conventions. The code generated put the [Key] attribute on the wrong field. In fact, it could not detect any uniqueness, so it put the [Key] attribute on all the fields.

I was able to remove all of the extra Key attributes to make the error go away.

Solution 3

Note for EF5+: .HasForeignKey has been deprecated from EF 5: List of available methods (https://msdn.microsoft.com/en-us/library/system.data.entity.modelconfiguration.configuration.manytomanyassociationmappingconfiguration_methods(v=vs.103).aspx) - MapLeftKey - MapRightKey - ToTable

If one were to need Many to Many where one 'Many' is to an Entity with a CompositeKey is:

one.HasKey(t => new { t.TwoId, t.ThreeId });
one.HasRequired(t => t.Two)
    .WithMany(s => s.Ones)
    .Map(m=>m.MapLeftKey("OneId").MapRIghtKey(new string[]{"TwoId", "ThreeId"}))
Share:
36,172
kmp
Author by

kmp

SO Careers Profile: http://careers.stackoverflow.com/kevinphillips LinkedIn: http://www.linkedin.com/in/kevinphillips

Updated on July 29, 2020

Comments

  • kmp
    kmp over 3 years

    I am using Entity Framework 4.3.1 against a SQL Server 2012 database and I am using the POCO approach. I am getting the following error and I am wondering if anyone can explain how to fix it:

    ModelValidationException

    One or more validation errors were detected during model generation: \tSystem.Data.Entity.Edm.EdmAssociationConstraint: : The number of properties in the Dependent and Principal Roles in a relationship constraint must be identical.

    There is no InnerException available for any further information.

    I cannot change the database schema and it is a little odd, but here it is...

    • ** are the primary key (notice I have composite primary keys)
    • (FK) Denotes a foreign key

    Here are the tables (if it helps I can post the SQL to generate them but I do not think the tables are actually the problem as the exception is in the validation of the model):

    One
    -
    **OneId int not null
    **TwoId int not null (FK)
    **ThreeId int not null (FK)
    Name nvarchar(50) not null
    
    Two
    -
    **TwoId int not null
    **ThreeId int not null (FK)
    Name nvarchar(50) not null
    
    Three
    -
    **ThreeId not null
    Name nvarchar(50) not null
    

    Here are the entities (notice that I am including the foreign keys in the model but other than that pretty standard):

    public class Three
    {
        public int ThreeId { get; set; }
        public string Name { get; set; }
        public virtual ICollection<Two> Twos { get; private set; }
        public virtual ICollection<One> Ones { get; private set; }
    
        public void AddOne(One one)
        {
            if (one == null)
                throw new ArgumentNullException("two");
    
            if (Ones == null)
                Ones = new List<One>();
    
            if (!Ones.Contains(one))
                Ones.Add(one);
    
            one.Three = this;
        }
    
        public void AddTwo(Two two)
        {
            if (two == null)
                throw new ArgumentNullException("two");
    
            if (Twos == null)
                Twos = new List<Two>();
    
            if (!Twos.Contains(two))
                Twos.Add(two);
    
            two.Three = this;
        }
    }
    
    public class Two
    {
        public int TwoId { get; set; }
        public int ThreeId { get; set; }
        public string Name { get; set; }
        public virtual Three Three { get; set; }
        public virtual ICollection<One> Ones { get; private set; }
    
        public void AddOne(One one)
        {
            if (one == null)
                throw new ArgumentNullException("two");
    
            if (Ones == null)
                Ones = new List<One>();
    
            if (!Ones.Contains(one))
                Ones.Add(one);
    
            one.Two = this;
        }
    }
    
    public class One
    {
        public int OneId { get; set; }
        public int TwoId { get; set; }
        public int ThreeId { get; set; }
        public virtual Two Two { get; set; }
        public virtual Three Three { get; set; }
    }
    

    And here is the data context:

    public class DbCtx : DbContext
    {
        public DbCtx(string connectionString)
            : base(connectionString)
        {
            Ones = Set<One>();
            Twos = Set<Two>();
            Threes = Set<Three>();
        }
    
        public DbSet<One> Ones { get; private set; }
        public DbSet<Two> Twos { get; private set; }
        public DbSet<Three> Threes { get; private set; }
    
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            var one = modelBuilder.Entity<One>();
            one.ToTable("One");
    
            one.HasKey(d => new
                                {
                                    d.OneId,
                                    d.TwoId,
                                    d.ThreeId
                                });
    
            one.Property(d => d.OneId)
                .HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
    
            one.HasRequired(t => t.Two)
                .WithMany(s => s.Ones)
                .HasForeignKey(t => t.TwoId);
    
            one.HasRequired(t => t.Three)
                .WithMany(s => s.Ones)
                .HasForeignKey(t => t.ThreeId);
    
            var two = modelBuilder.Entity<Two>();
            two.ToTable("Two");
    
            two.HasKey(d => new
                                {
                                    d.TwoId,
                                    d.ThreeId
                                });
    
            two.Property(p => p.TwoId)
                .HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
    
            two.HasRequired(t => t.Three)
                .WithMany(s => s.Twos)
                .HasForeignKey(t => t.ThreeId);
    
            var three = modelBuilder.Entity<Three>();
            three.ToTable("Three");
            three.HasKey(s => s.ThreeId);
    
            three.Property(p => p.ThreeId)
                .HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
    
            base.OnModelCreating(modelBuilder);
        }
    }
    

    Finally, this is a snippet of code to cause the exception:

    using (var ctx = new DbCtx(@"....."))
    {
        Console.WriteLine(ctx.Twos.Count());
    }