вторник, 3 февраля 2009 г.

LINQ to SQL Как получить случайную запись из таблицы SQL Server

Мне нужно было получить случайную запись из определенной таблицы в базе данных SQL Server.
В моем случае у меня была таблицы цитат и мне нужно было случайным образом выбирать запись(или записи) для отображения на веб-сайте. Кроме того я использовал LINQ to SQL на этом сайте, таким образом решение должно использовать эту технологию и, кроме того, быть достаточно простым и универсальным.

Идея заключалась в сортировке записей по случайному параметру а затем получении TOP n количества записей. Функция NEWID() из SQL Server выглядит хорошим кандидатом для получения случайного параметра, так как она генерирует GUID.

В SQL Server, попробуйте следующий запрос:


SELECT * FROM Quote ORDER by NEWID();


SELECT TOP 1 * FROM Quote ORDER by NEWID();


Сейчас для для нашего кода мы должны сгенерировать подобное поведение на .NET. Мне нужно было получить эквивалент NEWID() в моем LINQ to SQL DBML. Отмечу, что мы не можем непосредственно использовать NEWID() в хранимой процедуре или функции, так как SQL Server выдаст ошибку: “Invalid use of side-effecting or time-dependent operator in 'newid' within a function”. В обход этого мы создадим view который использует NEWID() и функцию, которая будет выбирать из этого view.


CREATE VIEW [dbo].[RandomView]
AS
SELECT NEWID() As ID
GO
CREATE FUNCTION [dbo].[GetNewId]
(
)
RETURNS uniqueidentifier
AS
BEGIN
RETURN (SELECT ID FROM RandomView)
END
GO


В DBML, мы просто перетащим таблицу Quote, а затем функцию GetNewID в дизайнер. Следующий код выбирает случайную запись из таблицы Quotes.


DataContext db = new QuoteDataContext();
var quote = db.Quote.OrderBy(q => db.GetNewId()).First();


Фактически мы можем выбирать любое количество записей из любой таблицы.