Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
408 views
in Technique[技术] by (71.8m points)

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

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: System.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());
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...