我正在使用Entity Framework 6(POCO,代码优先方法),我有以下情况......
我有一个具有枚举属性的实体(称为Status) - 数据库中的值是一个整数,我想要做的是向用户显示该值的本地化描述。
因此,我的代码看起来像这样(实际上,它调用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
,我当然会得到以下例外:
发生了'System.NotSupportedException'类型的异常 mscorlib.dll但未在用户代码中处理
其他信息: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个状态值),最糟糕的是,我无法重复使用它(但它至少可以工作)。
一开始简单方法的优点在于,因为还有其他具有Status列的实体,它们具有相同的可能值,我可以调用相同的方法。现在,如果我添加一个新的状态值,例如我必须通过我的代码搜索所有执行此转换的地方。可怕。
那么,是否有人知道如何创建可重用的代码片段,可以将其转换为可以插入Select
方法的SQL表达式?
我可以用Expression
编织一些魔法吗?
答案 0 :(得分:0)
是不是将枚举值转换为显示代码应该处理的人类可读文本?返回Enum并在将数据绑定到View之前将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)
});
答案 1 :(得分:0)
我找到了一种方法来做到这一点。项目LinqKit正是我所需要的,甚至还有一个方便的Nuget package,所以我做了:
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();
正如您所看到的,我可以Invoke Select中的表达式,并且在针对数据库的查询中恰好发生了正确的事情。
像这样,我可以很轻松地分享我的小方法。因此,我是一个快乐的兔子,正如你所看到的,我也不需要提前评估查询。