Пейджинг и сортировка на основе пользовательских свойств .NET с Linq to SQL - PullRequest
2 голосов
/ 16 августа 2011

Это продолжение этого вопроса о пользовательской подкачке в ASP.NET.

Скажем, у меня определена таблица:

CREATE TABLE Person
(
  ID int identity(1,1) not null primary key,
  FirstName varchar(50),
  LastName varchar(50)
)

И он сопоставлен с классом через конструктор Linq to SQL. Я определил это свойство в классе Person:

public string Name
{
  get
  {
    if (FirstName != null && FirstName != "" && LastName != null && LastName != "")
      return String.Format("{0} {1}", FirstName, LastName);
    else if (FirstName == null || FirstName == "")
      return LastName;
    else if (LastName == null || LastName == "")
      return FirstName;
    else
      return "";
  }
}

Скажем, у меня есть сетка, которая сортируется по столбцу, связанному с этим свойством Name, и я хочу сделать пейджинг. Естественный способ сделать это с помощью Linq to SQL - это что-то вроде:

MyDBContext db = new MyDBContext();
var myData = db.Persons.OrderBy(p => p.Name).Skip(pageSize * pageIndex).Take(pageSize);
myGrid.DataSource = myData;
myGrid.DataBind();

Linq to SQL выдает здесь ошибку, потому что не может преобразовать свойство Name в SQL . Я могу поместить .AsEnumerable() в строку фильтров, как отмечено в ответе на вопрос, на который я только что ссылался, но это означает, что я перетаскиваю все строки на веб-сервер и сортирую их там, что не идеально, если их достаточно записи в таблице. Фильтрация и сортировка должны происходить в базе данных.

Простой ответ - преобразовать это свойство Name в SQL и сделать его частью SPROC, который возвращает данные, или представление, или что-то еще. Но мне это не подходит, потому что я помещаю логику отображения в слой своей базы данных. Еще хуже, если ситуация будет более сложной, чем мой несколько надуманный пример, и определенное свойство будет более нетривиальным.

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

Ответы [ 2 ]

1 голос
/ 16 августа 2011

Я думаю, что ваше беспокойство по поводу разделения логики отображения и базы данных является необоснованным, или, скорее, я думаю, что идея о том, что логикой свойства Name является логика отображения, является

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

IMO, в вашей таблице Persons должен быть столбец с именем Name, и выдолжна иметь логику на вашем бизнес-уровне, которая выполняет преобразование других свойств в свойство Name, а затем сохраняет его вместе с остальными данными.

Тогда вы сможете выполнить обычный запроси порядок на уровне БД (и, возможно, в ваших данных есть и другие случаи, когда это также пригодится).

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

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

1 голос
/ 16 августа 2011

LINQ to SQL хочет выполнить запрос и сортировку на сервере - он может сделать это, если выражение можно перевести на SQL.

Ваш код в его нынешнем виде не переводится, поэтому вы получаете сообщение об ошибке.

Однако, если вы выполните рефакторинг запроса для вычисления имени, он будет работать:

var query = from p in db.Persons 
            let name = (p.FirstName + " " + p.LastName).Trim
            order by name  
            take 10
            select name;

Если вы попробуете запустить это, вы обнаружите, что LINQ-to-SQL хорошо выполняет перевод для вас:

SELECT [t2].[value]
        FROM (
            SELECT TOP (10) [t1].[value]
            FROM (
                SELECT LTRIM(RTRIM(([t0].[FirstName] + @p0) + [t0].[LastName])) AS [value]
                FROM [dbo].[Persons] AS [t0]
                ) AS [t1]
            ORDER BY [t1].[value]
            ) AS [t2]
        ORDER BY [t2].[value]

Однако, если стол станет больше, я бы рекомендовал против этого. Вы просите SQL выполнить вычисление несколько раз, в идеале это можно сделать один раз и сохранить. Рассмотрим вычисляемое поле FullName, в котором хранится результат. Это не потребует никаких вычислений и может быть проиндексировано.

...