Regex Заменить, чтобы помочь Orderby в LINQ - PullRequest
3 голосов
/ 22 декабря 2008

Я использую LINQ to SQL для извлечения записей из базы данных, сортировки их по строковому полю, а затем выполняю некоторые другие операции с ними. К сожалению, поле Имя, по которому я сортирую, выходит из базы данных, как это

Name
ADAPT1
ADAPT10
ADAPT11
...
ADAPT2
ADAPT3

Я бы хотел отсортировать поле Имя в числовом порядке. Прямо сейчас я использую объект Regex, чтобы заменить «ADAPT1» на «ADAPT01» и т. Д. Затем я снова сортирую записи, используя другой запрос LINQ. Код, который я имею для этого, выглядит как

    var adaptationsUnsorted = from aun in dbContext.Adaptations
                              where aun.EventID == iep.EventID
                              select new Adaptation
                              {
                                  StudentID = aun.StudentID,
                                  EventID = aun.EventID,
                                  Name = Regex.Replace(aun.Name,
                                     @"ADAPT([0-9])$", @"ADAPT0$1"),
                                  Value = aun.Value
                              };

    var adaptationsSorted = from ast in adaptationsUnsorted
                            orderby ast.Name
                            select ast;

    foreach(Adaptation adaptation in adaptationsSorted)
    {
        // do real work
    }

Проблема в том, что цикл foreach генерирует исключение

System.NotSupportedException was unhandled
  Message="Method 'System.String Replace(System.String, System.String,
    System.String)' has no supported translation to SQL."
  Source="System.Data.Linq"

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

Ответы [ 3 ]

2 голосов
/ 22 декабря 2008

Принудительная гидратация элементов путем перечисления запроса (вызов ToList). С этого момента ваши операции будут выполняться с объектами в памяти, и эти операции не будут преобразованы в SQL.

List<Adaptation> result =
  dbContext.Adaptation
  .Where(aun => aun.EventID = iep.EventID)
  .ToList();

result.ForEach(aun =>
  aun.Name = Regex.Replace(aun.Name,
    @"ADAPT([0-9])$", @"ADAPT0$1")
);
result = result.OrderBy(aun => aun.Name).ToList();
1 голос
/ 22 декабря 2008

Реализуйте IComparer<string> с вашей логикой:

var adaptationsUnsorted = from aun in dbContext.Adaptations
                          where aun.EventID == iep.EventID
                          select new Adaptation
                          {
                              StudentID = aun.StudentID,
                              EventID = aun.EventID,
                              Name = aun.Name,
                              Value = aun.Value
                          };

var adaptationsSorted = adaptationsUnsorted.ToList<Adaptation>().OrderBy(a => a.Name, new AdaptationComparer ());

foreach (Adaptation adaptation in adaptationsSorted)
{
    // do real work
}

public class AdaptationComparer : IComparer<string>
{
    public int Compare(string x, string y)
    {
        string x1 = Regex.Replace(x, @"ADAPT([0-9])$", @"ADAPT0$1");
        string y1 = Regex.Replace(y, @"ADAPT([0-9])$", @"ADAPT0$1");
        return Comparer<string>.Default.Compare(x1, y1);
    }
}

Я не тестировал этот код, но он должен выполнять свою работу.

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

Интересно, можете ли вы добавить вычисляемое + постоянное + индексированное поле в базу данных, это сделает это за вас. Было бы довольно просто написать UDF, который получает значение в виде целого числа (просто используя строковые значения), но затем вы можете отсортировать этот столбец в базе данных. Это позволит вам эффективно использовать Skip и Take, а не постоянно извлекать все данные в код .NET (который просто не масштабируется).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...