2012-10-12 312 views
8

Tengo una entidad, llamémosla CommonEntity que tiene una clave principal utilizada como clave foránea en muchas otras entidades. A medida que se desarrolla la aplicación, estos enlaces seguirán creciendo.Entity Framework: compruebe todas las relaciones de una entidad para el uso de la clave externa

Deseo obtener una forma de ver si CommonEntity se puede eliminar de forma segura (es decir, no es utilizado por ninguna otra entidad).

que se dan cuenta de que puedo hacer

if(!ce.EntityA.Any() && !ce.EntityB.Any() ... && !ce.EntityN.Any()) 
{ 
    //Delete 
} 

pero estoy esperando una manera de sólo comprobar todas las relaciones de forma automática, ya que no me gusta la idea de tener que volver y cambiar este código de forma manual cada vez que agregamos una nueva relación. Quizás hay algo en EF4 + que no conozco?

Pensé que podría ser posible utilizar un ámbito de transacción para simplemente tratar de eliminar el objeto y deshacerlo si falla, pero no estaba seguro de si hubo algún efecto secundario adverso con este enfoque.

¿Hay un mejor enfoque?

EDIT: Parece que VS2012 ha utilizado EF5 a pesar de que el proyecto es .Net 4, por lo que ha creado el modelo con POCOs aunque se haya generado desde un DB.

Respuesta

8

sólo deja que falle. Si la entidad tiene muchas relaciones, esa verificación podría ser muy pesada.

public bool TryDelete(int id) 
{ 
    try 
    { 
     // Delete 
     return true; 
    } 
    catch (SqlException ex) 
    { 
     if (ex.Number == 547) return false; // The {...} statement conflicted with the {...} constraint {...} 
     throw; // other error 
    } 
} 
+0

Si lo dejo fallar, ¿revertirá automáticamente cualquier conexión en cascada exitosa sin un ámbito de transacción? – BenC3

+1

Encontré la respuesta: SaveChanges() usa una transacción, por lo que cualquier falla se revertirá: http://msdn.microsoft.com/en-us/library/bb336792.aspx – BenC3

+0

No es bueno en absoluto si mantiene sus entidades abiertas ! – bytecode77

4

Puede probar esto:

var allrelatedEnds = ((IEntityWithRelationships)ce).RelationshipManager.GetAllRelatedEnds(); 
bool hasRelation = false; 
foreach (var relatedEnd in allrelatedEnds) 
{ 
    if (relatedEnd.GetEnumerator().MoveNext()) 
    { 
     hasRelation = true; 
     break; 
    } 
} 

if (!hasRelation) 
{ 
    //Delete 
} 
+0

Después de investigar un poco, parece que VS2 012 usa una versión de EF5 incluso cuando se usa como destino de .Net 4, por lo que cuento corto es que generó POCOs para mí aunque genere el modelo desde un DB, así que no puedo convertirlo a 'IEntityWithRelationships'. ¡Es malo por no mencionarlo! – BenC3

2

Puede utilizar la reflexión para esto (si no desea que su uso "Fail Eliminar en SQL") escribo esto porque yo no quiero borrar Entidad, sólo quiero saber si su relación con cualquiera o no!

public static object GetEntityFieldValue(this object entityObj, string propertyName) 
     { 
      var pro = entityObj.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance).First(x => x.Name == propertyName); 
      return pro.GetValue(entityObj, null); 

     } 

public static IEnumerable<PropertyInfo> GetManyRelatedEntityNavigatorProperties(object entityObj) 
     { 
      var props = entityObj.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(x => x.CanWrite && x.GetGetMethod().IsVirtual && x.PropertyType.IsGenericType == true); 
      return props; 
     } 

public static bool HasAnyRelation(object entityObj) 
     { 

       var collectionProps= GetManyRelatedEntityNavigatorProperties(entityObj); 


       foreach (var item in collectionProps) 
       { 
        var collectionValue = GetEntityFieldValue(entityObj,item.Name); 
        if (collectionValue != null && collectionValue is IEnumerable) 
        { 
         var col = collectionValue as IEnumerable; 
         if (col.GetEnumerator().MoveNext()) 
         { 
          return true; 
         } 

        } 
       } 
       return false; 
} 

en cuenta que: Contexto debe no se desechan y Proxy debe estar habilitado y saber que conseguirá grabar todas las relacionadas con la memoria (es demasiado pesado)

+1

Esta es una muy buena manera, creo, en lugar de hacer 'MyClass.Any() || MyOtherClass.Any() 'etc etc. Lo único que agregué fue un atributo Ignorar que le permite decidir No Incluir la' Propiedad' en 'HasAnyRelation()' El 'GetManyRelatedEntityNavigatorProperties()' se parece a esto ... 'var props = entityObj.. GetType() GetProperties (BindingFlags.Public | BindingFlags.Instance). .Where (x => x.CanWrite && x.GetGetMethod() IsVirtual && && x.PropertyType.IsGenericType (x.GetCustomAttribute (typeof (IgnoreIsDeletableAttribute)) == nulo) ); ' – Gwasshoppa

0

En primer lugar encontramos la entidad que desea eliminar el uso de Buscar en EF y pasar la entidad a la función siguiente ... Si la función devuelve verdadero significa que no se puede eliminar y existen datos extranjeros. Si la función devuelve falso significa que no hay registros padre o hijo y puede eliminarse.

public static bool DeleteCheckOnEntity(object entity) 
    { 
    var propertiesList = entity.GetType().GetProperties(); 
    return (from prop in propertiesList where prop.PropertyType.IsGenericType select prop.GetValue(entity) into propValue select propValue as IList).All(propList => propList == null || propList.Count <= 0); 
    } 
Cuestiones relacionadas