linq - first - entity framework español
EF 4: Eliminar el objeto hijo de la colección no lo elimina, ¿por qué? (5)
Utilizo Entity Framework 4 y tengo una relación padre-hijo con el conjunto "Cascade Delete". Así que esperaría cuando eliminé un elemento secundario del elemento primario que el elemento secundario se elimina cuando llamo a SaveChanges ().
cuRepository.Attach(_controlUnit);
foreach (var recipe in recipes) {
_controlUnit.Recipes.Remove(recipe);
//repository.DeleteObject(recipe);
}
En cambio, recibo un error:
Se produjo System.InvalidOperationException Message = Falló la operación: no se pudo cambiar la relación porque una o más de las propiedades de clave foránea no admiten nulos. Cuando se realiza un cambio en una relación, la propiedad de clave foránea relacionada se establece en un valor nulo. Si la clave externa no admite valores nulos, se debe definir una nueva relación, se debe asignar a la propiedad de clave externa otro valor no nulo o se debe eliminar el objeto no relacionado.
Cuando elimino explícitamente a los niños (vea la línea comentada), todo está bien. ¿Qué me estoy perdiendo?
No está eliminando el objeto con la instrucción remove. En su lugar, está intentando alterar un registro y hacerlo huérfano (estableciendo la clave foránea en nulo). La base de datos tiene una restricción no nula en esa columna e impide que lo haga.
Si hace que la relación entre el niño y el padre sea identificable, puede eliminar las entidades secundarias de la colección. Debe hacer que la clave del hijo sea una clave compuesta que contenga la clave de identificación primaria del padre. De esa forma, EF sabe que necesita eliminar al niño.
La relación de identificación básicamente dice que si el padre no existe, entonces el niño no tiene ningún significado. Esto significa que EF sabe que es seguro eliminar al niño cuando se elimina la relación.
Consulte esta pregunta. Identificar la relación e insertar entidades secundarias provoca "No se puede insertar un valor explícito para la columna de identidad en la tabla" y esta ¿Es posible eliminar elementos secundarios de la colección y resolver problemas en SaveChanges?
Utilizo esta extensión para no agregar un método en DAL solo para eliminar una entidad (código tomado de http://blogs.msdn.com/b/alexj/archive/2009/06/08/tip-24-how-to-get-the-objectcontext-from-an-entity.aspx ):
public static void Delete<T>(this EntityCollection<T> collection, T entityToDelete) where T : EntityObject, IEntityWithRelationships
{
RelationshipManager relationshipManager = entityToDelete.RelationshipManager;
IRelatedEnd relatedEnd = relationshipManager.GetAllRelatedEnds().FirstOrDefault();
if (relatedEnd == null)
{
throw new Exception("No relationships found for the entity to delete. Entity must have at least one relationship.");
}
var query = relatedEnd.CreateSourceQuery() as ObjectQuery;
if (query == null)
{
throw new Exception("The entity to delete is detached. Entity must be attached to an ObjectContext.");
}
query.Context.DeleteObject(entityToDelete);
collection.Remove(entityToDelete);
}
Entonces, Order.Products.Delete(prod)
una entidad como Order.Products.Delete(prod)
.
Las restricciones para usar la extensión son:
- La entidad debe tener relaciones;
- La entidad debe estar asociada a ObjectContext.
agregar context.DeleteObject(recipe)
dentro del ciclo
http://weblogs.asp.net/zeeshanhirani/archive/2010/07/23/removing-entity-from-a-related-collection.aspx explica exactamente lo que te sucedió.
Suponiendo que tienes un diseño de clase, algo como esto:
Entity Framework generará las columnas de clave foránea requeridas y agregará restricciones NOT NULL
a ellas, ya que todas las Recetas siempre estarán asociadas con exactamente una ControlUnit.
Por lo tanto, en tiempo de ejecución tendrá objetos similares al siguiente diseño:
Ahora su código entra en juego y elimina la relación entre los objetos Recipe y su ControlUnit:
Al tratar de guardar en este momento, la base de datos no tiene una ID de ControlUnit para poner en la columna de clave externa NOT NULL
. El estado del objeto actual infringe el diagrama de clase anterior y no se puede guardar en un diseño de base de datos generado bajo la suposición de que cada receta está asociada a una ControlUnit. Esta es la razón por la cual la base de datos se niega a guardar los cambios y usted ve la excepción.
Esto también explica por qué funciona cuando descomenta la línea que borra la entidad: la entidad se elimina de la base de datos junto con su relación, por lo que no se violan las restricciones, por lo tanto, no es una excepción.
"Pero me puse ON DELETE CASCADE
en la relación ..."
Sí, pero eso solo se desencadena al eliminar el objeto, no al eliminar la relación. Con el conjunto ON DELETE CASCADE
, esto debería funcionar:
controlUnitRepository.DeleteObject(_controlUnit);
// deletes the ControlUnit and all associated Recipe entities
Si desea activar la eliminación de las entidades de receta al eliminar su relación con ControlUnit, su relación no debe ser una simple asociación, sino una composición:
EF no admite esto de forma nativa, pero puede emular el comportamiento utilizando relaciones de identificación. Una vez que una entidad se encuentra en una relación de identificación con una entidad matriz y esa relación se elimina, la entidad también se elimina. Parece que esta era tu intención desde el principio. Para obtener más información sobre la identificación de relaciones, consulte Implementación de relaciones de identificación con EF4 donde implementé la identificación de relaciones con EF4 y he vinculado a más material de lectura.