2011-11-21 18 views
14

El código de Entity Framework First puede generar la base de datos para las siguientes POCO.Código de Entity Framework Primero: la restricción FOREIGN KEY puede causar ciclos o varias rutas en cascada

public class Item { 
    public int Id { get; set; } 
    public string Name { get; set; } 
} 

public class ItemPair { 
    public int Id { get; set; } 

    public virtual Item FirstItem { get; set; } 
    public virtual Item SecondItem { get; set; } 
} 

me gustaría establecer la relación con el primer y segundo elemento a través de campos de ID en lugar de la totalidad de una clase de "artículo". Entonces:

public class ItemPair { 
    public int Id { get; set; } 

    public virtual Item FirstItem { get; set; } 
    public int FirstItem_Id { get; set; } 

    public virtual Item SecondItem { get; set; } 
    public int SecondItem_Id { get; set; } 
} 

también funciona. Editar: Esto realmente no funcionó. Solo genera columnas FirstItem_Id1 y SecontItem_Id2 adicionales.

Pero sólo cambiar las propiedades de clave externa a FirstItemId, SecondItemId, (sin éste), así:

public class ItemPair { 
    public int Id { get; set; } 

    public virtual Item FirstItem { get; set; } 
    public int FirstItemId { get; set; } 

    public virtual Item SecondItem { get; set; } 
    public int SecondItemId { get; set; } 
} 

resultados en la siguiente excepción.

{"Introducing FOREIGN KEY constraint 'ItemPair_SecondItem' on table 'ItemPair' may cause 
cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, 
or modify other FOREIGN KEY constraints.\r\nCould not create constraint. 
See previous errors."} 

¿Por qué? Y qué puedo hacer para evitar esta excepción.

+0

Esta alternativa me ayudó a mejorar http://stackoverflow.com/questions/19373310/introducing-foreign-key-constraint-may-cause-cycles-or-multiple-cascade-paths – Mzn

Respuesta

17

Mi expectativa es que en el primer caso sus propiedades Id no se utilicen en la base de datos ya que FKs y EF crearán otras dos columnas (puede validar forzando el emparejamiento de la propiedad de navegación con propiedad FK usando ForeignKeyAttribute). En el segundo caso, EF reconocerá correctamente sus propiedades, pero también utilizará la convención de eliminación en cascada que causará un error en el servidor SQL. Tiene dos propiedades de la tabla que apuntan al mismo elemento primario. De hecho, en la base de datos puede crear ItemPair desde el mismo Item (ambos FK configurados con el mismo Id). Si ambas relaciones tienen habilitada la eliminación en cascada, se generarán varias rutas en cascada => no permitidas en el servidor SQL.

La solución aquí es el mapeo fluido para definir manualmente cómo se mapean las relaciones. Here es el ejemplo.

+0

Muchas gracias por esto. Pasé unas horas tratando de resolverlo. No se me ocurrió leer las convenciones de eliminación en cascada. – Pauly

21

Decidí eliminar la convención de eliminación en cascada.

protected override void OnModelCreating(DbModelBuilder modelBuilder) { 
     base.OnModelCreating(modelBuilder); 

     modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>(); 
     modelBuilder.Conventions.Remove<ManyToManyCascadeDeleteConvention>(); 

    } 

Las razones son:

  • prefiero marcar registros eliminados o desactivados para fines de auditoría.
  • Como máximo borro solo las tablas de unión/mapeo.
  • Con un ORM Es relativamente trivial recorrer y borrar registros secundarios en el caso raro que necesito.

Gracias Ladislav Mrnka me apunta en la dirección correcta.

+0

Gracias a Dios, había leído otra respuesta a una pregunta similar y pensé que tendría que hacer todo mi mapeo basado en atributos como fluido. En mi humilde opinión, EF intenta hacer demasiado por defecto. – Josh

+0

Me sentí de la misma manera, así que comencé con la asignación basada en atributos también. Sin embargo, ahora uso las asignaciones de API Fluent porque parece que me da más control, así como mantener mi POCO libre de cruft.Intente instalar las "herramientas de poder de Entity Framework" y realice una ingeniería inversa de su base de datos actual. Creo que una vez que veas las asignaciones que genera, no se sentirá tan extraño. – Pauly

+0

¡Esto se ve genial! Pero lamentablemente no funcionó en mi caso. Lo que no entiendo es cómo puedo llamar a WillCascadeOnDelete (falso) en cada relación, y eliminar esta convención, y aún en mis scripts SQL (listado detallado). Puedo ver que crea la restricción ofensiva. Al final de este comando está "ON DELETE CASCADE", a pesar de todo mi trabajo en mapeos fluidos para eliminar este comportamiento. –

Cuestiones relacionadas