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 ...
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());
}
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
.
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"}))
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.