database - tutorial - scaffold dbcontext postgresql
¿Cómo eliminar entidades secundarias antes que padre con Entity Framework CF? (7)
Bueno, la solución más sencilla sería recorrer los precios primero y llamar a los cambios guardados, luego configurar la entrada para eliminar para deleteMe y volver a llamar los cambios guardados, pero ¿has comprobado esto: el código del marco de la entidad primero elimina con cascada ? Parece ser lo que quieres.
Aunque también es curioso, ¿por qué no elimina las entidades del contexto para eliminar sino que establece el estado de entrada?
Otra opción es configurar la eliminación en cascada http://blogs.msdn.com/b/alexj/archive/2009/08/19/tip-33-how-cascade-delete-really-works-in-ef.aspx
Haga algo como esto (no probado, pero espero que obtenga el jist):
using (TransactionScope scope = new TransactionScope())
{
foreach (var deleteMe in deleteThese)
{
// Delete validation
if(CanDeleteItem(deleteMe.ItemId))
{
foreach (var item in deleteMe.Prices)
{
db.Entry(item).State = EntityState.Deleted; // cascade delete
}
db.SaveChanges();
db.Entry(deleteMe).State = EntityState.Deleted;
}
}
db.SaveChanges();
scope.Complete();
}
Además puedes llamar a:
db.Prices.Remove(item);
y
db.DeleteMes.Remove(deleteMe);
En lugar de establecer el estado de entrada. Sin embargo, no estoy seguro de si hay una diferencia entre bambalinas.
Estoy tratando de usar el código EF primero para eliminar un registro db ( deleteMe
) y sus hijos ( deleteMe.Prices
).
foreach (var deleteMe in deleteThese)
{
// Delete validation
if(CanDeleteItem(deleteMe.ItemId))
{
db.Entry(deleteMe).State = EntityState.Deleted;
foreach (var item in deleteMe.Prices)
{
db.Entry(item).State = EntityState.Deleted; // cascade delete
}
}
}
db.SaveChanges();
Sin embargo, Entity Framework parece ser incapaz de rastrear el hecho de que los registros secundarios deben eliminarse antes que los padres. Me sale el error
La instrucción DELETE entró en conflicto con la restricción REFERENCE "ItemPrice_Item".
El conflicto se produjo en la base de datos "DEVDB", tabla "dbo.ItemPrices", columna ''Item_ItemId''.
La instrucción se ha terminado.
¿Cómo ejecutaría esta eliminación en EF?
EF6
context.Children.RemoveRange(parent.Children)
La eliminación en cascada en EF depende de la eliminación en cascada configurada en relación con la base de datos, por lo que si no tiene la eliminación en cascada configurada en la base de datos, primero debe cargar todos los precios de los artículos en su aplicación y marcarlos como eliminados.
La eliminación en cascada en Entity framework es un asunto delicado, ya que necesita estar seguro acerca de la eliminación del gráfico del objeto de la entidad. Es mejor escribir siempre una prueba de integración para estas eliminaciones en cascada.
Si intenta eliminar la entidad principal en EF, intentará ejecutar las instrucciones de eliminación para cualquier entidad secundaria en el dbcontext actual. Como resultado, no inicializará ninguna entidad secundaria que no se haya cargado. Esto conducirá a un error de tiempo de ejecución de RDBMS que viola la restricción de clave externa. Para estar seguro, asegúrese de que todas las entidades dependientes cargadas en dbcontext actual antes de eliminarlas.
Si su objeto se refiere a sí mismo, puede eliminar niños de muchos a muchos y de uno a muchos utilizando el método que se encuentra a continuación. Solo recuerda llamar a db.SaveChanges () después :)
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public ActionResult DeleteConfirmed(int id)
{
Object obj = this.db.Objects.Find(id);
this.DeleteObjectAndChildren(obj);
this.db.Objects.Remove(obj);
this.db.SaveChanges();
return this.Json(new { success = true });
}
/// <summary>
/// This deletes an object and all children, but does not commit changes to the db.
/// - MH @ 2016/08/15 14:42
/// </summary>
/// <param name="parent">
/// The object.
/// </param>
private void DeleteObjectAndChildren(Object parent)
{
// Deletes One-to-Many Children
if (parent.Things != null && parent.Things.Count > 0)
{
this.db.Things.RemoveRange(parent.Things);
}
// Deletes Self Referenced Children
if (parent.Children != null && parent.Children.Count > 0)
{
foreach (var child in parent.Children)
{
this.DeleteObjectAndChildren(child);
}
this.db.Objects.RemoveRange(parent.Children);
}
}
Tenía un problema similar y, para mí, parecía que no había establecido correctamente la relación entre padres e hijos en sus respectivas clases.
Mi solución fue agregar los atributos especificados a continuación a la clase secundaria, para la propiedad que representaba su ID de padre
public class Child
{
[Key, Column(Order = 1)]
public string Id { get; set; }
[Key, ForeignKey("Parent"), Column(Order = 2)] // adding this line fixed things for me
public string ParentId {get; set;}
}
public class Parent
{
[Key, Column(Order = 1)]
public string Id { get; set; }
...
public virtual ICollection<Child> Children{ get; set; }
}
Terminé encontrando una línea rápida que lo haría por mí:
foreach (var deleteMe in deleteThese)
{
// Delete validation
if(CanDeleteItem(deleteMe.ItemId))
{
///
deleteMe.Prices.ToList().ForEach(p => db.ItemPrices.Remove(p));
///
db.Entry(deleteMe).State = EntityState.Deleted;
}
}
db.SaveChanges();