Linq To SQL: сохранить порядок списков при использовании .Contains - PullRequest
3 голосов
/ 31 декабря 2010

Я использую Lucene.net для создания MyListOfIds As List(Of Integer), который я затем передаю своей службе Linq.Затем я выполняю поиск в базе данных следующим образом:

Return _EventRepository.Read().Where(Function(e) MyListOfIds.Contains(e.ID)).ToList

Теперь я знаю, что Lucene уже заказывает MyListOfIds в зависимости от веса, который он дал каждому термину.Отвратительно, что Linq теряет этот порядок в поиске SQL.

Мой вопрос: Как мне сохранить этот порядок сортировки при построении лямбда-выражения?

Я пыталсяиспользуя LINQPad , чтобы увидеть, как строится запрос, но из-за того, что мне пришлось объявить переменную LINQPad , я не показал результирующий SQL:то, что я пробовал в LINQPad

Dim i As New List(Of Integer)
i.Add(1)
i.Add(100)
i.Add(15)
i.Add(3)
i.Add(123)

Dim r = (From e In Events
         Where i.Contains(e.ID)
         Select e)

примечание: мой пример в VB.NET, но я не против, если ответы находятся в C #

Ответы [ 5 ]

2 голосов
/ 31 декабря 2010

Как уже говорилось, я думаю, что метод словаря - это путь. Я бы поступил так:

Public Function GetLuceneSearchResults(ByVal ids As List(Of Integer)) As List(Of Domain.Event) Implements IEventService.GetLuceneSearchResults
    Dim Results = (From e In _EventRepository.Read()
                   Where ids.Contains(e.ID)
                   Select e).ToDictionary(Function(e) e.ID, Function(e) e)

    Return (From i In ids
            Where Results.ContainsKey(i)
            Select Results(i)).ToList()
End Function

Первый запрос возвращает словарь с идентификатором события в качестве ключа и само событие в качестве значения. Таким образом вы получаете выигрыш в производительности при поиске хеша.

2 голосов
/ 31 декабря 2010

Получите неупорядоченные результаты обратно из запроса L2S, затем измените порядок в том же порядке, что и список в запросе L2O (linq-to-objects), используя перегрузку .Select, которая задает порядковый номер позиции . E.g.:

var someResult = _EventRepository.Read().Where(e => MyListOfIds.Contains(e.ID)).ToList();

var someResultOrdered =
  from sr in someResult
  join lid in MyListOfIds.Select((v, i) => new { v, i }) on sr.ID equals lid.v
  orderby lid.i
  select sr;
2 голосов
/ 31 декабря 2010

Я бы сказал, что запрос LINQ to SQL будет возвращать данные в естественном порядке базы данных (вероятно, первичный ключ?), Потому что условие IN в SQL (что и должно быть переведено .Contains) не указывайте ORDER и ваше выражение LINQ. Если вы думаете об этом как в обычном SQL-выражении, становится очевидным, что вы не можете легко определить порядок таким образом.

Чтобы отсортировать загруженные данные, вы можете отсортировать их, а затем отсортировать перечисление по известному порядку из Lucene. Вам, вероятно, придется написать это самостоятельно (например, клиент IComparer<T>).

1 голос
/ 31 декабря 2010

ОП Ответ

@ Похоже, из-за повешения я думал правильно. Вот что я придумала ...

открыт для предложений!

    Public Function GetLuceneSearchResults(ByVal ids As List(Of Integer)) As List(Of Domain.Event) Implements IEventService.GetLuceneSearchResults
        Dim Results = _EventRepository.Read().Where(Function(e) ids.Contains(e.ID)).AsQueryable
        Dim Output As New List(Of Domain.Event)

        For Each i In ids
            Output.Add(Results.Where(Function(e) e.ID = i).SingleOrDefault)
        Next

        Return Output
    End Function

Теперь рассмотрим спекуляции с производительностью, это определенно работает точно так, как ожидалось. Мне бы очень хотелось услышать ваши мысли по поводу улучшения производительности или если это просто выход на обед. Спасибо.

1 голос
/ 31 декабря 2010

Возможно, вам понадобится IDictionary, и ваш ключ будет просто инкрементным (например, столбец идентификаторов) и значение вашего фактического идентификатора из Lucene.

Затем в своем операторе LINQ2SQL вместо этого условия "где" вы можете выполнить "соединение" в словарном значении со столбцом в вашей БД. В вашем LINQ сортируйте по ключу словаря.

РЕДАКТИРОВАТЬ: ДОБАВЛЕННЫЙ ПРИМЕР

Вот пример:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1 {
    class Program {
        static void Main(string[] args) {

            var ids = new Dictionary<int, int>();

            //key is just a sort sequence, value is the ID from Lucene
            ids.Add(1, 27);
            ids.Add(2, 25);
            ids.Add(3, 29);

            var ctx = new DataClasses1DataContext();

            var tabs = (from t in ctx.Tabs
                         where ids.Values.Contains(t.TabID)
                         select t).ToList();


            var sorted = from t in tabs
                         join id in ids on t.TabID equals id.Value
                         orderby id.Key
                         select t;

            foreach (var sortedItem in sorted) {
                Console.WriteLine(sortedItem.TabID);
            }
            Console.ReadLine();


        }
    }

}

...