如何解决:关系约束中从属角色和主角色的属性数量必须相同?

35
我正在使用Entity Framework 4.3.1访问SQL Server 2012数据库,并采用POCO方法。 我遇到了以下错误,想知道是否有人能够解释如何解决:

ModelValidationException

在模型生成期间检测到一个或多个验证错误: \tSystem.Data.Entity.Edm.EdmAssociationConstraint:关系约束中从属角色和主角色中的属性数必须相同。

没有可用的InnerException以获取更多信息。

我无法更改数据库架构,这有点奇怪,但是它在这里...

  • **是主键(请注意,我有组合主键)
  • (FK)表示外键

以下是表格(如果需要,我可以发布生成它们的SQL,但我认为表格实际上不是问题所在,因为异常在模型验证中):

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

以下是实体(注意我在模型中包含了外键,但除此之外非常标准):

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

以下是数据上下文:

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

最后,这是一个导致异常的代码片段:
using (var ctx = new DbCtx(@"....."))
{
    Console.WriteLine(ctx.Twos.Count());
}
3个回答

52
错误的原因是您模型中的关系配置不正确。以下内容是不正确的:
    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);

应该是:

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

因为依赖外键必须包含主键的所有列。您还必须从ThreeOne中删除导航属性。


1
太好了,谢谢 - 我已经为此苦恼了一段时间! - kmp

3

这也可能是由从数据库生成的Code First引起的。

我引入了几个视图,根据Entity Framework规则,它们没有明显的关键字段。生成的代码将[Key]属性放在了错误的字段上。实际上,它无法检测到任何唯一性,因此将[Key]属性放在了所有字段上。

我成功地删除了所有额外的Key属性,使错误消失了。


在我的情况下,我正在添加一个 ForeignKey 引用,但它与 EF 在视图上创建的无效 Composite Key 冲突。 - Hans Vonn

2
注意EF5+版本: 自EF5起,HasForeignKey方法已被弃用:可用的方法列表如下(https://msdn.microsoft.com/en-us/library/system.data.entity.modelconfiguration.configuration.manytomanyassociationmappingconfiguration_methods(v=vs.103).aspx) - MapLeftKey - MapRightKey - ToTable 如果需要一个“多”对应到具有复合主键的实体的“多对多”,则:
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"}))

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接