【问题标题】:How to make a formatted string property into a linq-to-entity friendly expression?如何将格式化的字符串属性转换为 linq-to-entity 友好表达式?
【发布时间】:2015-04-14 02:53:59
【问题描述】:

在最近的EF Code First 项目中,我们尝试使用不同的技术优化一些 Linq 查询(不要担心这还不算早)。优化 linq 查询的一种常见方法是将更多表达式从 Linq-to-Objects 转换为几乎所有 Linq-to-Entities 端,这通常比将 Linq-to-Objects 和 Linq-to-Entities 与 lazy loading 混合更快。

我已经阅读了如何为大多数可转换为 Linq-To-Entities 的查询创建 linq 表达式,但我不确定如何使用 object initializer syntax 执行此操作。

举个例子:

return results.Select(x => new { Name = x.FullName });  

来自下落的例子Person类:

public class Person
{
        public string FullName
        {
            get { return FirstName + " " + LastName; }
        }

        public string FirstName { get; set; }

        public string LastName { get; set; }

}  

现在,我可以将第一个表达式转换为 Linq-to-Entity 友好表达式:

return results.Select(x => new { Name = x.FirstName + " " + x.LastName});   

但是这种情况很糟糕,因为我正在复制 FullName 的逻辑。现在您可以说对于这样一个微不足道的示例来说这无关紧要,但不难想象具有更复杂的只读属性的情况。

无论如何,我正在尝试弄清楚是否有办法做这样的事情:

return results.Select(x => new { Name = Person.FullNameExpression(x) });  

谁能告诉我这样的事情在 Linq-to-entities 中是否可行,而不使用 Linq-to-objects?

如果这是不可能的,我能得到的最接近的方法是防止在我的实体上重复只读属性的逻辑?

【问题讨论】:

    标签: c# entity-framework ef-code-first linq-to-entities object-initializers


    【解决方案1】:

    无论如何,我正在尝试弄清楚是否有办法做这样的事情:

    简单的出路:

    你根本做不到。如果您希望逻辑仅存在于单个位置,则它只能在单个位置中运行。作为 .Net 类的只读属性意味着它只能作为本地对象运行。如果您不希望该逻辑存在,则必须将其发送到(sql)服务器。

    少有人走的路:

    我相信从技术上讲,您可以创建一个可以在本地 Person 或服务器端匿名类型上运行的 expression,但我个人认为,除非您熟悉表达式树,否则这可能是矫枉过正且不易维护的代码。

    【讨论】:

    • 感谢您的关注,是的,我正在寻找是否有某种形式的表达解决方案,而不是本地对象解决方案。
    • 谢谢,我去看看。
    • 我不确定链接到解决方案是否一定对对象初始化语法友好的 linq-to-entties,但我会在今天晚些时候试一试。
    • 这个想法是有一个可以应用于任何对象并返回 FullName 的表达式(封装)。因此,在您的 EF 中,如果您返回了一个带有 FirstNameLastName 的匿名对象,那么您将在该 lambda 表达式的末尾应用您的 FullName 表达式。在接下来的几周里,我实际上正在学习表达式,我会先试试这个。在我得出任何具体结论之前可能还需要一段时间。
    【解决方案2】:

    在使用“数据库优先”方法时,我通常将计算/只读属性放在部分类中。这些计算的字段/属性根本没有映射,因为它们不存在于我的数据库表中。因此,当我获取填充名字和姓氏的人员时,对 person 类上的 fullname 属性的调用将即时构造值。和你的例子一模一样。

    首先我对代码不太满意,但是您也可以在您的 person 类上完美地设置只读属性。您唯一需要做的就是通过未映射的属性或通过 DbModelBuilder.Ignore 告诉 EF 该属性未映射。

    那么就不需要复制全名逻辑了。从数据库中获取人员后,可以通过访问属性获得全名。

    results.Select(person => person.Fullname)

    【讨论】:

    • 感谢您的关注,但如果我按照您的建议进行操作,那么我将不会在 linq-to-entities 中评估该属性,但必须将其拉入具有我相信,性能比 linq-to-entities 差。
    • 我想这取决于。 Linq to objects 是“在内存中”,所以我认为性能下降可以忽略不计。当您想在(SQL)服务器端过滤“表达式”时,您可能会得到 field1 + ' ' + field2 比较语句。有效地使 SQL 服务器无法使用许多索引。这可能会更加损害性能。因此,在过滤服务器端时,您可能希望仅出于这个原因使用持久化字段。
    • 我一直在通过使用不同的度量来衡量性能,很少有东西在 linq-to-objects 中比 linq-to-entities 更快。但除此之外,我需要将此特定字段转换为 linq 到实体,因为我需要检索其他属性,以便我可以优化除全名部分之外的查询的其余部分。这只是一个示例属性。所以不,我不能使用 linq-to-objects。
    • 我理解这是一个人为的例子。而且我也不提倡使用 Linq-to-Objects。重点是警告表达式语句可能会导致您的数据库服务器无法适当地优化您的查询。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多