Пользовательский синтаксис расширения Linq - PullRequest
2 голосов
/ 09 декабря 2008

Я написал функцию, которая получает определенное количество случайных записей из списка. В настоящее время я могу сделать что-то вроде:

IEnumerable<City> cities = db.Cites.GetRandom(5);

(где db - мой DataContext, соединяющийся с БД SQL Server)

В настоящее время у меня есть такая функция в каждой сущности, из которой мне нужны случайные записи:

public partial class City
{

    public static IEnumerable<City> GetRandom(int count)
    {
        Random random = new Random();
        IEnumerable<City> cities = DB.Context.Cities.OrderBy( c => random.Next() ).Take(count);

        return cities;
    }

}

Он отлично работает, но я бы хотел, чтобы он был универсальным, чтобы он мог работать для любой таблицы или даже для любого списка элементов. Я пробовал метод расширения, как:

    public static IEnumerable<T> GetRandom<T>( this Table<T> table, int count)
    {
        Random random = new Random();
        IEnumerable<T> records = table.OrderBy(r => random.Next()).Take(count);

        return records;
    }

но я получаю:

  Error 1   The type 'T' must be a reference type in order to use it as parameter 'TEntity' in the generic type or method 'System.Data.Linq.Table' 

, который выделяет GetRandom<T>.

Я не понимаю, в чем здесь проблема. Может кто-нибудь прояснить правильный синтаксис?

Ответы [ 4 ]

6 голосов
/ 09 декабря 2008

Мне нравится идея функции случайного порядка, и она может применяться к любому IEnumerable следующим образом:

public static IEnumerable<T> Randomize<T>(this IEnumerable<T> source)
{
    Random rnd = new Random();
    return source.OrderBy(t => rnd.Next());
}

...

IEnumerable<City> cities = db.Cites.Randomize().Take(5);
5 голосов
/ 09 декабря 2008

Если вы разговариваете с базой данных, вы можете сделать случайный выбор в базы данных. С LINQ-to-SQL вы можете (для небольших томов) сделать это через [Function], указывающую на NEWID (в контексте данных):

     [Function(Name="NEWID", IsComposable=true)] 
     public Guid Random() 
     { 
         return Guid.NewGuid(); 
     } 

затем в запросе через:

     ctx.Log = Console.Out; 
     var query = from x in ctx.Suppliers 
                 orderby ctx.Random() 
                 select x; 
     var results = query.ToArray(); 

, который дает TSQL (здесь используется Northwind):

SELECT [t0].[SupplierID], [t0].[CompanyName], [t0].[ContactName], 
[t0].[ContactTitle], [t0].[Address], [t0].[City], [t0].[Region], 
[t0].[PostalCode], [t0].[Country], [t0].[Phone], [t0].[Fax], [t0].[HomePage] 
FROM [dbo].[Suppliers] AS [t0] 
ORDER BY NEWID() 

Очевидно, вы можете смешать это с Take (1) и т. Д.

Это не работает в рамках сущности, хотя.

4 голосов
/ 09 декабря 2008

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

Я думаю, что это правильный способ определения ограничений типа:

public static IEnumerable<T> GetRandom<T>( this Table<T> table, int count) where T : class {
  ...
}

Подробнее об ограничениях типов здесь

0 голосов
/ 09 декабря 2008

Попробуйте это

public static IEnumerable<T> GetRandom<T>( this Table<T> table, int count) where T : class {
  ...
}
...