web-dev-qa-db-ja.com

修正方法:関係制約の依存ロールとプリンシパルロールのプロパティの数は同じでなければなりませんか?

SQL Server 2012データベースに対してEntity Framework 4.3.1を使用しており、POCOアプローチを使用しています。私は次のエラーを受け取っていますが、誰かがそれを修正する方法を説明できるかどうか疑問に思っています:

ModelValidationException

モデル生成中に1つ以上の検証エラーが検出されました:\ 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());
}
30
kmp

エラーの理由は、モデル内の関係が正しく構成されていないことです。これは正しくありません:

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

従属のFKには、プリンシパルPKのすべての列が含まれている必要があるためです。 ThreeからOneへのナビゲーションプロパティも削除する必要があります。

45
Ladislav Mrnka

EF5 +に関する注意:.HasForeignKeyはEF 5から非推奨になりました:利用可能なメソッドのリスト( https://msdn.Microsoft.com/en-us/library/system.data.entity.modelconfiguration.configuration.manytomanyassociationmappingconfiguration_methods( v = vs.103).aspx )-MapLeftKey-MapRightKey-ToTable

CompositeKeyを持つエンティティに対する「多」が1つである多対多が必要な場合:

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"}))
2
OzBob

これは、 データベースの最初のコード によっても発生する可能性があります。

Entity Frameworkの規則に従って、明確なキーフィールドを持たない意見を取り入れました。生成されたコードは、[Key]属性を間違ったフィールドに配置しました。実際、一意性を検出できなかったため、すべてのフィールドに[Key]属性を設定しました。

エラーをなくすために、余分なキー属性をすべて削除することができました。

2
Jess