c# - resuelto - mpm.mx/sudoku 2018
Cómo solucionarlo: ¿El número de propiedades en los roles de dependiente y principal en una restricción de relación debe ser idéntico? (3)
Estoy usando Entity Framework 4.3.1 contra una base de datos de SQL Server 2012 y estoy usando el enfoque POCO. Recibo el siguiente error y me pregunto si alguien puede explicar cómo solucionarlo:
ModelValidationException
Se detectaron uno o más errores de validación durante la generación del modelo: / tSystem.Data.Entity.Edm.EdmAssociationConstraint:: El número de propiedades en los Roles dependientes y principales en una restricción de relación debe ser idéntico.
No hay InnerException
disponible para más información.
No puedo cambiar el esquema de la base de datos y es un poco extraño, pero aquí está ...
- ** son la clave principal (aviso tengo claves primarias compuestas)
- (FK) denota una clave externa
Aquí están las tablas (si me ayuda puedo publicar el SQL para generarlas pero no creo que las tablas sean realmente el problema, ya que la excepción está en la validación del modelo):
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
Aquí están las entidades (observe que estoy incluyendo las claves foráneas en el modelo pero que no son bastante estándar):
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; }
}
Y aquí está el contexto de los datos:
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);
}
}
Finalmente, este es un fragmento de código para causar la excepción:
using (var ctx = new DbCtx(@"....."))
{
Console.WriteLine(ctx.Twos.Count());
}
El motivo del error son las relaciones configuradas incorrectamente en su modelo. Esto no es correcto:
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);
Debería ser:
one.HasRequired(t => t.Two)
.WithMany(s => s.Ones)
.HasForeignKey(t => new { t.TwoId, t.ThreeId });
Porque el FK del dependiente debe contener todas las columnas de la PK principal. También debe eliminar la propiedad de navegación de Three
a One
.
Esto también puede ser causado por el código primero de la base de datos .
Tuve varias opiniones que presenté que no tenían un campo clave obvio según las convenciones de Entity Framework. El código generado pone el atributo [Key]
en el campo incorrecto. De hecho, no pudo detectar ninguna singularidad, por lo que puso el atributo [Key]
en todos los campos.
Pude eliminar todos los atributos clave adicionales para que el error desaparezca.
Nota para EF5 +: .HasForeignKey ha quedado en desuso en EF 5: Lista de métodos disponibles ( https://msdn.microsoft.com/en-us/library/system.data.entity.modelconfiguration.configuration.manytomanyassociationmappingconfiguration_methods(v=vs.103).aspx ) - MapLeftKey - MapRightKey - ToTable
Si uno necesitara de Muchos a Muchos, donde un ''Muchos'' es para una Entidad con un CompositeKey es:
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"}))