web-dev-qa-db-fra.com

Comment résoudre ce problème: Le nombre de propriétés dans les rôles dépendants et principaux dans une contrainte de relation doit être identique?

J'utilise Entity Framework 4.3.1 sur une base de données SQL Server 2012 et j'utilise l'approche POCO. J'obtiens l'erreur suivante et je me demande si quelqu'un peut expliquer comment y remédier:

ModelValidationException

Une ou plusieurs erreurs de validation ont été détectées lors de la génération du modèle:\tSystem.Data.Entity.Edm.EdmAssociationConstraint:: le nombre de propriétés dans les rôles dépendants et principaux dans une contrainte de relation doit être identique.

Il n'y a pas de InnerException disponible pour plus d'informations.

Je ne peux pas changer le schéma de la base de données et c'est un peu étrange, mais le voici ...

  • ** sont la clé primaire (notez que j'ai des clés primaires composites)
  • (FK) Indique une clé étrangère

Voici les tables (si cela peut aider je peux poster le SQL pour les générer mais je ne pense pas que les tables soient réellement le problème car l'exception est dans la validation du modèle):

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

Voici les entités (notez que j'inclus les clés étrangères dans le modèle mais à part cela assez 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; }
}

Et voici le contexte des données:

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

Enfin, il s'agit d'un extrait de code pour provoquer l'exception:

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

La raison de l'erreur provient de relations mal configurées dans votre modèle. Ce n'est pas 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);

Ça devrait être:

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

Parce que le FK de la personne à charge doit contenir toutes les colonnes de PK principal. Vous devez également supprimer la propriété de navigation de Three à One.

45
Ladislav Mrnka

Remarque pour EF5 +: .HasForeignKey a été déconseillé de EF 5: Liste des méthodes disponibles ( https://msdn.Microsoft.com/en-us/library/system.data.entity.modelconfiguration.configuration.manytomanyassociationmappingconfiguration_methods (( v = vs.103) .aspx ) - MapLeftKey - MapRightKey - ToTable

Si l'on avait besoin de plusieurs à plusieurs, où un "plusieurs" est pour une entité avec une CompositeKey, c'est:

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

Cela peut également être causé par Code d'abord de la base de données .

J'ai eu plusieurs vues que j'ai apportées qui n'avaient pas de champ clé évident selon les conventions Entity Framework. Le code généré a mis le [Key] attribut sur le mauvais champ. En fait, il n'a pu détecter aucun caractère unique, il a donc mis le [Key] attribut sur tous les champs.

J'ai pu supprimer tous les attributs de clé supplémentaires pour faire disparaître l'erreur.

2
Jess