2012-01-20 35 views
7

El código representan pequeña escala de mi problema:referencia a sí misma con Entity Framework

public class Category 
{ 
    public Guid CategoryID { get; set; } 
    public string Name { get; set; } 
    public Guid? ParentID { get; set; } 
    public bool IsTop { get; set; } 
    public string Description { get; set; } 

    public virtual Category parentCategory { get; set; } 
} 

Cuando uso esta clase en Entity Framework, genera sólo una relación de padre e hijo categorías.

Cómo puedo decir que separe semánticamente las propiedades y genere dos relaciones diferentes en SQL Server una para obtener todas las categorías secundarias con (relación hija hijo (recursivo descendente)) y la otra para obtener todas las categorías principales (padre de los padres (recursivo de abajo hacia arriba))? Algo como esto:

public virtual ICollection<Category> childCategories { get; set;} 
public virtual ICollection<Category> parentCategories { get; set;} 

Lo probé con modelBuilder pero a partir de ahí solo puedo obtener un nivel de detalle.

+0

¿Tiene padres múltiples por categoría o solo uno? Tampoco entiendo lo que quieres exactamente. ¿Desea una colección 'parentCategories' que contenga de alguna manera todas las categorías en el árbol hasta la raíz? En caso afirmativo, esto no sería una propiedad de navegación sino un tipo de evaluación o resultado de un recorrido. EF no lo ayudará, tiene que escribir su propio código para crear dicha colección. – Slauma

+0

sí exactamente. quiero algo así que me da todas las categorías de niños por el árbol y de la misma manera todas las categorías padre hasta el árbol ... y sí, me doy cuenta de que EF no ayudará en esta situación, así que he hecho algunos bucles recursivos de IEnmueble y funciona para mí ... gracias por su apoyo –

Respuesta

7

He tenido el problema de recuperar todos los nodos secundarios a una profundidad de n aparecen en uno de mis proyectos como la clásica relación de autorreferencia de supervisor/empleado en una tabla Employee en mi modelo. Como señalaron Slauma y Milracle, EF no lo ayudará a recuperar todos los nodos a una profundidad de n bajo un padre especificado. Sin embargo, pude resolver este problema usando un Breadth-first search algorithm en mi repositorio. Tenga en cuenta que mi objetivo no era solo recuperar todos los nodos secundarios, sino hacerlo rápidamente, ya que el uso de consultas LINQ recursivas llevaba más de dos minutos para los niveles superiores de administración. Usando este método, ahora se ejecuta en menos de dos segundos.

public IEnumerable<string> GetAllSubordinateEmployeeIdsByUserId(string userId) 
{ 
    // Retrieve only the fields that create the self-referencing relationship from all nodes 
    var employees = (from e in GetAllEmployees() 
        select new { e.Id, e.SupervisorId }); 
    // Dictionary with optimal size for searching 
    Dictionary<string, string> dicEmployees = new Dictionary<string, string>(employees.Count() * 4); 
    // This queue holds any subordinate employees we find so that we may eventually identify their subordinates as well 
    Queue<string> subordinates = new Queue<string>(); 
    // This list holds the child nodes we're searching for 
    List<string> subordinateIds = new List<string>(); 

    // Load the dictionary with all nodes 
    foreach (var e in employees) 
    { 
     dicEmployees.Add(e.Id, e.SupervisorId); 
    } 

    // Get the key (employee's ID) for each value (employee's supervisor's ID) that matches the value we passed in 
    var directReports = (from d in dicEmployees 
         where d.Value == userId 
         select d.Key); 

    // Add the child nodes to the queue 
    foreach (var d in directReports) 
    { 
     subordinates.Enqueue(d); 
    } 

    // While the queue has a node in it... 
    while (subordinates.Count > 0) 
    { 
     // Retrieve the children of the next node in the queue 
     var node = subordinates.Dequeue(); 
     var childNodes = (from e in dicEmployees 
          where e.Value == node 
          select e.Key); 
     if (childNodes.Count() != 0) 
     { 
      // Add the child nodes to the queue 
      foreach (var c in childNodes) 
      { 
       subordinates.Enqueue(c); 
      } 
     } 
     // Add the node from the queue to the list of child nodes 
     subordinateIds.Add(node); 
    } 

    return subordinateIds.AsEnumerable(); 
} 

Además, como nota al pie, yo era capaz de aumentar la eficiencia de look-ups en el diccionario con la ayuda de este Dictionary optimization artículo.

+0

¿No es esta solución hacer una búsqueda en solo dos niveles? Me estoy perdiendo de algo ? –

Cuestiones relacionadas