2009-08-31 2 views
3

Только что обновили с Subsonic 2.2 ActiveRecord до 3.0.0.3. Я пытаюсь использовать LINQ сделать постраничный Find запрос, как это (мой объект/таблица не называется «Repository»):Subsonic 3.0.0.3 SQL-пейджинг с использованием Linq

Repository.Find(item => item.DocumentTitle.Contains(searchTerm)) 
    .OrderBy(i => i.DocumentTitle).Skip((currentPage - 1) * itemsPerPage) 
    .Take(itemsPerPage); 

Когда я рассматриваю SQL, генерируемый этим запросом с помощью SQL Server Profiler, нет пейджинг в SQL, весь пейджинг выполняется в памяти на C#. Теперь у Subsonic-языка запросов есть хорошая процедура GetPaged, которая работает правильно, но я думал, что LINQ должен был это сделать. Я что-то пропустил или это ограничение LINQ?

Я знаю о функции Repository.GetPaged(), но у меня недостаточно параметров - мне нужно сделать динамический сортировку, а также Find().

ответ

5

После выполнения дальнейших испытаний, это утверждение работает правильно:

(from i in dataContext.Repositories 
where i.DocumentTitle.Contains(searchTerm) 
orderby i.DateCreated ascending select i) 
.Skip((currentPage - 1) * itemsPerPage).Take(itemsPerPage); 

При выполнении выше заявление LINQ приходит обратно правильно выгружаемого в SQL.

Единственный вывод, который я могу прийти к тому, что при использовании метода цепочек синтаксиса, когда вы находитесь за пределами исходного выражения лямбды

Repository.Find(item => item.DocumentTitle.Contains(searchTerm)) 

дозвукового интерпретатор SQL прекращает создание SQL для любых методов прикованных на конец

.OrderBy(i => i.DocumentTitle).Skip(15).Take(10); 

Или, я просто полностью делаю что-то неправильно здесь? У кого-нибудь есть понимание?

+0

Сделал еще больше исследований. По-видимому, это связано с тем, как C# компилирует выражение linq. Компилятор должен знать во время разработки, какое будет утверждение. Если это не так, утверждение не может быть отражено SubSonic «ExpressionVisitor» (это не уникально для SubSonic), потому что это уже не одно «выражение». – Steve

+0

Существуют библиотеки сторонних разработчиков, которые позволят вам создать ваш оператор linq несколькими шагами, но это добавит больше внешних зависимостей к вашему проекту. На данный момент у SubSonic есть некоторые из этих функций, но на данный момент я недостаточно знаю, поэтому предлагаю использовать их для этого. – Steve

1

Вы можете отсортировать GetPaged путем добавления «DESC» в поле сортировки, но ...

пейджинг должен работать - я смотрю на пейджинговой SQL передо мной, и это не сделано в памяти. Как вы это тестируете? Если вы используете «ToList()», который выполнит запрос, тогда посмотрите на профилировщик.

+0

Функция GetPaged была бы идеальной, за исключением того, что она мне нужна для выполнения Find(). Так что FindGetPaged(), если хотите. это SQL я см, проходящий через из запроса я отправил (я также попытался ToList (), я был Проходя мимо IEnumerable к ListView источника данных.): Exec sp_executesql N'SELECT [t0] [CategoryName] , [t0]. [DateCreated], [t0]. [DocumentFileType], [t0]. [DocumentTitle], [t0]. [FileContent], [t0]. [RepositoryId] FROM [dbo]. [mag_Repository] AS t0 WHERE ([t0]. [DocumentTitle] LIKE ''% '' + @ p0 + ''% '') ', N' @ p0 nvarchar (4000) ', @ p0 = N' ' – Steve

+0

Чтобы проверить это, я подключился к отладчику VS, запустил профайлер только для моей БД, а затем нарушил эту функцию: Список retList = репозиторий .Find (item => item.DocumentTitle.Contains (searchTerm)) .OrderByDescending (i => i.DocumentTitle) .Skip ((currentPage - 1) * itemsPerPage) .Take (itemsPerPage) .ToList (); и посмотреть, как заявление sql попадает в профиль, когда я нажимаю F10. – Steve

+0

Я также проверил GetPaged только для того, чтобы убедиться, что я правильно смотрю SQL, и он прошел правильно с помощью оператора sql-запроса RowNumber(). Поэтому я не понимаю, что я здесь делаю неправильно. – Steve

0

Немного поздно, но ...

Repository.Find() 

возвращает IList так, запрос выполняется, следовательно, SQL выполняет без подкачки затем

.Skip(x).Take(x) 

делается в памяти. Попробуйте

Repository.All().Where(expression).Skip(x).Take(x) 

все которые возвращают IQueryable и не из которых перечисляются объекты и так подкачки делается в SQL с помощью функции ROW_NUMBER().

Сказав, что Дозвуковые 3 просто хранилище генерирует следующий SQL

exec sp_executesql N'SELECT [t0].[Id], [t0].[IsDeleted], [t0].[Name], [t0].[ParentUuid], [t0].[Uuid] 
FROM (SELECT [t1].[Id], [t1].[IsDeleted], [t1].[Name], [t1].[ParentUuid], ROW_NUMBER() OVER() AS rownum, [t1].[Uuid] 
FROM [Sites] AS t1 
WHERE (([t1].[ParentUuid] = @p0) AND ([t1].[IsDeleted] = 0))) AS t0 
WHERE [t0].[rownum] BETWEEN (20 + 1) AND (20 + 10)',N'@p0 uniqueidentifier',@p0='00000000-0000-0000-0000-000000000000' 

, который бросает исключение

Unhandled Exception: System.Data.SqlClient.SqlException: The ranking function "ROW_NUMBER" must have an ORDER BY clause. 

так, казалось бы, что есть ошибка в дозвуковой :-(

+0

Я бы не сказал, что это ошибка SubSonic, потому что SubSonic переводит ваш запрос на простой sql. Поскольку исключения говорят о том, что у ROW_NUMBER должно быть предложение ORDER BY, вам нужно добавить ключевое слово orderby в ваш запрос linq, так что дозвуковое генерирует порядок тоже (btw. Mysql не генерирует исключение в этом случае, потому что LIMIT (x , y) не требует ORDER BY –

+0

Возможно, не ошибка, согласованная. Я обновил локальную сборку дозвуковых, чтобы проверить, добавлено ли предложение order by к любому запросу, содержащему функцию ROW_NUMBER, если нет порядка Я вставляю ORDER BY Id в часть OVER из ROW_NUMBER, тем самым избегая исключения. Это не идеально, и это зависит от среды (ВСЕ мои классы DOM ДОЛЖНЫ наследовать DomBase и иметь свойство ID). –

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