2013-06-03 2 views
2

У меня есть следующий код:Как изменить порядок сортировки в Linq-to-Sql?

IQueryable<Guid> GetOrdered(IQueryable<Guid> ids) 
{ 
    return from id in ids join storedId in storedIds on id equals storedId.Id 
     orderby storedId.Something select id; 
} 

Теперь я хочу, чтобы ввести параметр в GetOrdered() и, возможно, изменить orderby с orderby descending. Что-то вроде этого:

IQueryable<Guid> GetOrdered(IQueryable<Guid> ids, bool descending) 
{ 
    // how do I insert descending into the query below? 
    return from id in ids join storedId in storedIds on id equals storedId.Id 
     orderby storedId.Something select id; 
} 

Конечно, я мог бы написать два одинаковых запросов - один с orderby, а другой с orderby descending, но это означает, что дублирование кода.

В качестве альтернативы я мог бы использовать суб-заявление для неупорядоченного набора, а затем условно заказать его like in this answer но проблема мне тогда нужно Select() конкретный столбец и что последний Select() будет оказывать неупорядоченный результат.

Так что я мог бы попытаться выработать «умное» состояние заказа в in this answer:

var result = from w in widgets where w.Name.Contains("xyz") 
    orderby 
    flag ? w.Id : 0, 
    flag ? 0 : w.Id descending 
    select w; 

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

Как я могу условно отменить порядок сортировки в этих условиях?

+0

Я не понимаю, почему вы не можете использовать решение «подзаголовок с условным порядком»? – Magnus

+0

@Magnus: Это потому, что он будет сначала «упорядочен», затем «отфильтрован» без какого-либо определенного порядка. – sharptooth

+0

@sharptooth Если вы выполняете 'select' после' orderby', 'select' не изменяет порядок результатов. (Хотя я мог ошибаться, возможно, LINQ-to-objects предоставляет больше гарантии здесь, чем делает LINQ-to-SQL.) – Rawling

ответ

4
IQueryable<Guid> GetOrdered(IQueryable<Guid> ids, bool descending = false) 
{ 
    var results = from id in ids join storedId in storedIds on id equals storedId.Id 
        select id; 

    if (descending) 
     results = results.OrderByDescending(o => o.Something); 
    else 
     results = results.OrderBy(o => o.Something); 

    return results; 
} 

Это своего рода стандартный материал.

Однако, если вам нужно заказать что-то, что вы на самом деле не выбрали, вам нужно разделить запрос на несколько операторов. Вы знаете, постройте запрос шаг за шагом, как мы это сделали в дни ADO. Сначала сделайте заказ, а затем укажите столбцы для выбора. Поскольку вы не материализуете результаты, он должен генерировать только один SQL-запрос.

Это может выглядеть так.

IQueryable<Guid> GetOrdered(IQueryable<Guid> ids, bool descending = false) 
{ 
    var results = storedIds.Where(somecondition);   
    if (descending) 
     results = results.OrderByDescending(o => o.Something); 
    else 
     results = results.OrderBy(o => o.Something); 

    return results.Select(o => o.Id); 
} 

О вашем последнем предложении ..

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

Это правда. Возможно, есть способ преодолеть это (например, использовать какую-то фабрику, которая будет генерировать значение для сравнения на основе какого-либо ввода), но это действительно избыток для такой задачи. Иногда самое простое решение - лучшее. Слишком общие способы делать вещи могут сильно пахнуть. Не overthink проблемы;)

+1

Это точно так же, как решение, которое он сказал, что он не может использовать. – Magnus

1

Для достижения условной OrderBy в Linq, вы могли бы сделать что-то вроде этого:

var flag = sortOrder == "asc"; 

result.OrderBy(o => flag ? o.Something: "").ThenByDescending(o => flag ? "" : o.Something).ToList(); 

работает для меня.