2012-03-09 130 views
3

我有以下對象結構。遞歸linq查詢

public class Study 
{ 
    public Guid? PreviousStudyVersionId { get; set; } 
    public Guid StudyId { get; set; } 
    //Other members left for brevity 
} 

它首先使用實體​​框架代碼持久化。

它導致一個表像這樣

PreviousStudyVersionId     StudyId 
EF90F9DC-C588-4136-8AAE-A00E010CE87B E4315CFD-9638-4225-998E-A00E010CEEEC 
NULL         1C965285-788A-4B67-9894-3D0D46949F11 
1C965285-788A-4B67-9894-3D0D46949F11 7095B746-8D32-4CC5-80A9-A00E010CE0EA 
7095B746-8D32-4CC5-80A9-A00E010CE0EA EF90F9DC-C588-4136-8AAE-A00E010CE87B 

現在我想查詢所有studyId的遞歸。所以我想出了以下解決方案:

因此,當我在我的存儲庫GetAllStudyVersionIds(新Guid(「7095B746-8D32-4CC5-80A9-A00E010CE0EA」))中調用該方法時,它將所有4返回給studyId。

public IEnumerable<Guid> GetAllStudyVersionIds(Guid studyId) 
    { 
     return SearchPairsForward(studyId).Select(s => s.Item1) 
      .Union(SearchPairsBackward(studyId).Select(s => s.Item1)).Distinct(); 
    } 

    private IEnumerable<Tuple<Guid, Guid?>> SearchPairsForward(Guid studyId) 
    { 
     var result = 
      GetAll().Where(s => s.PreviousStudyVersionId == studyId).ToList() 
      .Select(s => new Tuple<Guid, Guid?>(s.StudyId, s.PreviousStudyVersionId)); 
     result = result.Traverse(a => SearchPairsForward(a.Item1)); 
     return result; 
    } 

    private IEnumerable<Tuple<Guid, Guid?>> SearchPairsBackward(Guid studyId) 
    { 
     var result = GetAll().Where(s => s.StudyId == studyId).ToList() 
      .Select(s => new Tuple<Guid, Guid?>(s.StudyId, s.PreviousStudyVersionId)); 
     result = result.Traverse(a => a.Item2.HasValue ? SearchPairsBackward(a.Item2.Value) : Enumerable.Empty<Tuple<Guid, Guid?>>()); 
     return result; 
    } 

這是我的擴展方法的實現。

public static class MyExtensions 
{ 
    public static IEnumerable<T> Traverse<T>(this IEnumerable<T> source, Func<T, IEnumerable<T>> fnRecurse) 
    { 
     foreach (var item in source) 
     { 
      yield return item; 
      var seqRecurse = fnRecurse(item); 
      if (seqRecurse == null) continue; 
      foreach (var itemRecurse in Traverse(seqRecurse, fnRecurse)) 
      { 
       yield return itemRecurse; 
      } 
     } 
    } 
} 

是否有任何方法將此接近數據庫(IQueryable)並優化此代碼。

+0

您最終可能會/想寫一個SQL查詢。不同的數據庫平臺可以做到這一點。 MS SQL Server可以通過[遞歸CTE](http://msdn.microsoft.com/zh-cn/library/ms186243.aspx)執行此操作。 – vcsjones 2012-03-09 13:55:10

+0

從列的名稱猜測,您正在有效地創建歷史項目的鏈接列表。可能存在一種不同的存儲方式,這更適合於關係模型,例如,有一張學習桌,還有一張桌子上擺滿了參考它的歷史項目。 – OlduwanSteve 2012-03-09 14:09:02

回答

1

我已經完成了這項工作,通過遞歸表函數根據id提取所有父記錄,然後創建一個視圖爲每條記錄和所有父母生成一個列表。然後我在EF模型中使用它,並將它與LINQ配合使用。