2012-03-09 3 views
3

У меня есть следующая структура объекта.Рекурсивный запрос linq

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

Он сохраняется сначала с использованием сущности Framework.

Это приводит к таблице, как этот

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 исследования.

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/en-us/library/ms186243.aspx). – vcsjones

+0

Угадав имена столбцов, вы фактически создаете связанный список элементов истории. Может быть способ хранения этого по-разному, который лучше подходит для реляционной модели, например. с таблицей исследования и таблицей с элементами истории, которые относятся к ней. – OlduwanSteve

ответ

1

Я сделал это, создав рекурсивную функцию таблицы, потянув все родительские записи на основе id, а затем создав представление для создания списка для каждой записи и всех родителей. Затем я использую это в модели EF и ассоциирую с возможностью использования с LINQ.

Смежные вопросы