C# 使用Linq to SQL基于自定义.NET属性的分页和排序

C# 使用Linq to SQL基于自定义.NET属性的分页和排序,c#,asp.net,linq-to-sql,custompaging,C#,Asp.net,Linq To Sql,Custompaging,这是关于ASP.NET中自定义分页的后续内容 假设我定义了一个表: CREATE TABLE Person ( ID int identity(1,1) not null primary key, FirstName varchar(50), LastName varchar(50) ) 我通过LINQtoSQL设计器将其映射到一个类。我已在Person类上定义了此属性: public string Name { get { if (FirstName != nul

这是关于ASP.NET中自定义分页的后续内容

假设我定义了一个表:

CREATE TABLE Person
(
  ID int identity(1,1) not null primary key,
  FirstName varchar(50),
  LastName varchar(50)
)
我通过LINQtoSQL设计器将其映射到一个类。我已在
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();
但是,LINQtoSQL在这里抛出了一个错误,因为它是。我可以将
.AsEnumerable()
放入过滤器字符串中,正如我刚才提到的问题的答案中所述,但这意味着我将所有行拉到web服务器并在那里排序,如果表中有足够的记录,这并不理想。应在数据库中进行筛选和排序

简单的答案是将
Name
属性转换为SQL,并使其成为返回数据、视图或其他内容的存储过程的一部分。但我觉得这不对,因为我把显示逻辑放在了数据库层中。如果情况比我精心设计的示例更复杂,并且定义的属性更重要,那么情况就更糟了


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

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重复执行一次计算,理想情况下可以执行一次并存储。考虑计算字段FulnNew,它存储结果。这将不需要计算,并且可以编制索引。

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

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

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

然后,您将能够正常查询,并在DB级别进行排序(在您的数据中可能还有其他情况下,这也会很方便)

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


另一种思考方式是,你要做一些转换和写作。但是,您将多次读取此数据,并且每次都将执行此转换。如果您将执行此转换所花费的所有时间加在一起,这将是一笔可观的金额,如果您预先计算该值,然后在需要时对其执行适当的查询操作,则可以节省该金额。

这里有两个问题。首先,虽然此逻辑可转换为SQL,但并非所有复杂逻辑都可转换为SQL;如果逻辑变得比这更复杂,那么它可能无法转换,而你又回到了原点。第二个问题是,查询生成的SQL将给出与代码中的逻辑不同的结果。
LTRIM
RTRIM
运算符将返回
NULL
如果
NULL
被传递到它,但是在这种情况下,代码检查NULL并返回空值,结果将返回
NULL
。这与期望的输出不同。您应该更正代码以产生相同的输出。通过计算字段,您是指我从数据库中选择的视图而不是表中的某个内容吗?@Jefferson先生:您也不应该在视图中这样做;如果要重复查询,最好将值转换一次,存储它,然后在需要时查询该值。这里的假设是,读操作比写操作多得多。不,不是所有复杂的逻辑都可以翻译成SQL。如果SQL不能做到这一点,那么代码就必须做到,而要对一万条记录进行排序,需要对复杂函数进行一万次计算。每次你访问它。因此,如果您要使用它,请保存它。您认为UI中网格列绑定到的属性是否应该始终基于存储在DB中的字段,而不是动态计算?排除子元素计数等情况,即Mr。杰斐逊:这个问题没有一个明确的答案。这是关于用法的。如果你要把那列读一遍,它的写入次数与写入次数相比是非常少的,那么我绝对要说,它应该存储在数据库中。但是,如果该列被多次写入,但查询很少,那么我会将其留给显示器来执行转换。你必须衡量什么最适合你的系统。但是,以您的示例为例,您似乎有后一种情况(多读,少写)。