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...
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()); }
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
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With