2

这是关于 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()过滤器字符串,正如我刚刚引用的问题的答案中所述,但这意味着我将所有行拉到 Web 服务器并在那里对它们进行排序,如果有足够的记录在桌子。过滤和排序应该发生在数据库中。

简单的答案是将该Name属性转换为 SQL,并使其成为返回数据、视图或其他东西的 SPROC 的一部分。但这对我来说感觉不对,因为我将显示逻辑放在我的数据库层中。如果情况比我有点做作的例子更复杂,并且定义的属性更不平凡,那就更糟了。

有没有出路,还是我不得不在性能和关注点分离之间做出选择?或者我对数据库中那种显示逻辑的担心是没有根据的?

4

2 回答 2

1

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,它存储结果。这不需要计算并且可以被索引。

于 2011-08-16T17:43:23.193 回答
1

我认为您对显示逻辑和数据库分离的担忧是没有根据的,或者更确切地说,我认为Name属性背后的逻辑是显示逻辑的想法是。

在许多情况下,即使仅出于显示目的,也会预先计算值以帮助查询、显示和优化。

IMO,您的Persons表上应该有一个名为的列,Name并且您的业务层中应该有执行将其他属性转换为Name属性的逻辑,然后将其与其余数据一起保存。

然后,您将能够正常查询,并在数据库级别进行排序(并且您的数据中可能还有其他情况也可以派上用场)。

仅仅因为分页和排序将结果集过滤到可管理的级别并不意味着重复且经常执行显示逻辑操作是可以接受的。

另一种思考方式是,您将进行几次转换和编写。但是,您将多次读取此数据,并且每次都将执行此转换。如果您汇总执行此转换所花费的所有时间,它将加起来相当多,如果您预先计算该值,然后在需要时对其执行适当的查询操作,您可以节省大量时间。

于 2011-08-16T17:44:31.283 回答