2012-01-20 55 views
7

代码代表我的问题的小规模:自引用实体框架

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; } 
} 

当我在实体框架使用这个类,它产生只有一个父和子类别的关系。

我该如何判断语义上分离的属性,并在SQL Server中生成两个不同的关系:一个用于获取所有子类别(子关系的子对象(递归自上而下)),另一个用于获取所有父类别(父母的父母(递归自下而上))?这样的事情:

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

我试着用modelBuilder,但从那里我只能得到一个细节层次。

+0

您是否有多个父母或每个类别?我也不明白你想要什么。你想要一个集合'parentCategories',它包含树中的所有类别到根?如果是的话,这将不是导航属性,而是某种评估或遍历的结果。 EF不会帮助你,你必须编写你自己的代码来创建这样一个集合。 – Slauma

+0

是的。我想要类似的东西,它给我所有的孩子类别在树上,并以相同的方式,所有的父类别树... 和是的,我意识到EF不会在这种情况下帮助,所以我做了一些递归循环的IEnmuerable它对我有用.. 感谢您的支持 –

回答

7

我有一个问题,检索所有子节点到n的深度,在我的模型中的一个Employee表上作为经典的主管/员工自引用关系出现在我的一个项目中。正如Slauma和Milracle指出的那样,EF不会帮助您检索指定父级下的所有节点,深度为n。但是,我能够在我的存储库中使用Breadth-first search algorithm来解决此问题。请注意,我的目标不仅是要检索所有子节点,还要快速完成此操作,因为使用递归LINQ查询对于最高级别的管理需要超过两分钟。使用这种方法,它现在在不到两秒的时间内执行。

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(); 
} 

而且,作为一个注脚,我能够从这个Dictionary optimization文章有利于增加查找UPS的效率在字典。

+0

该解决方案是不是仅在两个级别进行搜索?我错过了什么吗? –