EF查询的select语句中的自定义扩展功能

时间:2013-03-30 10:52:57

标签: entity-framework

在我们的数据库中,我们有一个表格,我们已经映射到Database-First EF模​​型中的实体:

CREATE TABLE Texts(
  Id integer,
  Eng nvarchar(max),
  Nob nvarchar(max),
  ...
)

此表中的行可能非常大,因此我们只想获取用户所做语言选择当前所需列的值。

我的想法是有一个扩展功能为我做,但我没有任何想法,也没有找到任何方法来写它(如果它甚至可能)。我已经尝试了一些变体,但(显然)它失败了一个异常,声明它无法转换为存储表达式。所以我有点卡住了。

使用此功能的想法是:

context.Codes.Where(row => row.Id == 234).Select(row => new {
  row.Id,
  Text = Text.GetLocalizedText("Eng") // This should generate an SQL that only retrieves the Eng 
                                      // column of the Text navigation property (which is 
                                      // connected to the Texts table.
});

那应该生成一个与此类似的选择(除了直接使用Text.Eng之外,它与上面的例子相似):

SELECT 
[Extent1].[Id] AS [Id], 
[Extent2].[Eng] AS [Eng]
FROM  [dbo].[Codes] AS [Extent1]
INNER JOIN [dbo].[Texts] AS [Extent2] ON [Extent1].[TextId] = [Extent2].[Id]
WHERE 234 = [Extent1].[Id]

有谁知道这是否可行,如果可能的话;怎么写呢?如果不可能,有没有人对如何解决这个问题有任何其他的想法,而不用整个文本实体检索所有的列?

1 个答案:

答案 0 :(得分:0)

IQueryable<Code>的扩展方法可行,但它不像你想要的那样灵活,因为你需要为你想要执行的每种投影都有一个扩展,你不能使用匿名结果对象。

这个想法基本上是这样的:

您需要一个可以投射到的命名类(而不是匿名):

public class CodeData
{
    public int Id { get; set; }
    public string LocalizedText { get; set; }
}

然后是一个带语言参数的扩展方法:

public static class CustomExtensions
{
    public static IQueryable<CodeData> SelectCodeData(
        this IQueryable<Code> query, string language)
    {
        switch (language)
        {
            case "Eng":
                return query.Select(code => new CodeData
                {
                    Id = code.Id,
                    LocalizedText = code.Text.Eng
                });

            case "Nob":
                return query.Select(code => new CodeData
                {
                    Id = code.Id,
                    LocalizedText = code.Text.Nob
                });
            //... more languages
        }

        throw new ArgumentException("Invalid language code.", "language");
    }
}

然后可以像这样调用:

using CustomExtensions;

// ...

IQueryable<CodeData> codeDataQuery = context.Codes
    .Where(row => row.Id == 234)
    .SelectCodeData("Eng");