繁体   English   中英

从select调用方法时,是否可以说服Entity Framework进行表达式?

[英]Is it possible to convince the Entity Framework to make an expression when calling a method from a select?

我正在使用Entity Framework 6(POCO,代码优先方法),并且遇到以下情况...

我有一个实体,该实体的属性是枚举(称为状态)-数据库中的值是整数,我想向用户显示此值的本地化描述。

因此,我的代码看起来像这样(实际上,它调用ResourceManager并具有更多状态值,但这只是指示性的):

public static string ToDisplayable(Status status) 
{
    switch(status)
    {
        case Status.One:
            return "Status ONE";
        case Status.Two:
            return "Status TWO";
        default:
            return "Unknown Status";
     }
}

...

var results = someIqueryable
    .ToList()
    .Select(r => new 
    { 
        Status = r.Status, 
        DisplayableStatus = ToDisplayable(r.Status) 
    });

现在,这很好,因为toList当然很好,这意味着在调用Select之前,我所有的东西都已从数据库中撤回。 如果删除ToList我当然会得到以下例外:

mscorlib.dll中发生类型'System.NotSupportedException'的异常,但未在用户代码中处理

附加信息:LINQ to Entities无法识别方法'System.String ToDisplayable(Status)',并且该方法无法转换为商店表达式。

好吧,很公平,它不能将我的函数调用转换为SQL,也不能真正怪我。

事情是我真的,真的,真的不想说ToList在那里,因为后来一些Where条款可能(也可能不会)被添加,此外,我只是不需要对我的实体中的所有列。

因此,我认为我唯一的选择是这样做:

var results = someIqueryable
    .Select(r => new 
    { 
        Status = r.Status, 
        DisplayableStatus = r.Status ==  Status.One
            ? "Status ONE"
            :  r.Status ==  Status.Two
                ? "Status TWO"
                : "Unknown Status"
     });

这有点丑陋和乏味(在我的实际代码中大约有15个状态值),最糟糕的是,我无法重用它(但它至少可以工作)。

一开始,简单方法的优点在于,因为还有其他带有“状态”列的实体,它们具有相同的可能值,因此我可以调用同一方法。 现在,例如,如果我添加一个新的状态值,我必须遍历我的代码以查找进行此翻译的所有位置。 可怕。

因此,有人知道我如何创建可重用的代码段,这些代码段可翻译为可插入Select方法的SQL表达式吗?

我可以用一种Expression编织一些魔术吗?

将枚举值转换为可读文本不是显示代码应注意的事情吗? 在将数据绑定到View之前,返回Enum并将Enumeration转换为可显示的值。

在最坏的情况下,您始终可以执行以下操作:

var results = someIqueryable
    .Where(...)
    .Select(r => new Status = r.Status, /* other column you're after */)
    .ToList()
    .Select(r => new 
    { 
        Status = r.Status, 
        /* other column you're after */,
        DisplayableStatus = ToDisplayable(r.Status) 
    });

我想出了一种方法。 LinqKit项目正是我需要的,甚至还有一个方便的Nuget包,所以我做到了:

Install-Package LinqKit

我认为我正在使用的该库中的代码最初来自Tomas Petricek 我希望它在主要的Entity Framework项目中,但是无论如何...

现在,我已引用该库,我可以创建一个助手:

public static class StatusHelper
{
    public static readonly Expression<Func<Status, string>> ToDisplayable = s => 
        s == Status.One
            ? "Status ONE"
            : s == Status.Two
                ? "Status TWO"
                : "Unknown Status";
}

然后像这样使用该助手:

// It is important to assign to a local variable here and
// not attempt to use the StatusHelper in the query
// see - http://stackoverflow.com/q/22223944/1039947
// Not ideal, of course, but I can live with it
var toDisplayable = StatusHelper.ToDisplayable;

var results = someIqueryable
    .AsExpandable()  // <-- This is needed for LinqKit
    .Select(x => new 
    { 
        Status = x.Status, 
        DisplayableStatus = toDisplayable.Invoke(x.Status)
    })
    .ToList();

如您所见,我可以在Select中 调用表达式,并且在对数据库的查询中发生了正确的事情。

这样,我可以轻松地分享我的小方法。 因此,我是一个快乐的兔子,正如您所看到的,我也不需要尽早评估查询。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM