繁体   English   中英

使用EF模型从字符串字段存储和检索枚举的无缝方法

[英]Seamless way to store and retrieve enums from a string field using EF Model

我有几个代表状态的枚举,它们都对应于EF模型上的字符串字段。 选择所有枚举值,以便可以轻松地将它们表示为char,因此将它们设置如下:

public enum eStateCode
{
    Running = 'R',
    Terminated = 'T',
    Cancelled = 'C',
}

这样,数据库字段可以是char [1]类型,能够存储含义代码,而不是抽象的数字字段。 该方法使用Linq to SQL无缝运行,因为char SQL列映射到char字段,但不使用EF。

使用EF,当我尝试在这样的lambda表达式上使用它时

s => s.WFStateCode == ((char)ClassX.eStateCode.Running).ToString())

我得到了

LINQ to Entities无法识别该方法

错误,表示((char)ClassX.eStateCode.Running).ToString()已发送到SQL。

我可以通过将put ((char)ClassX.eStateCode.Running).ToString()放在变量中来解决问题,但是会使代码更加冗长。 我读了几篇文章,但没有人说我如何强迫EF在客户端解析表达式的一部分。

可以定义一个可以在lambda表达式中用作文字的方法,因此它不会发送到SQL吗?

该错误意味着EntityFramework无法将您的代码转换为SQL。 您可以在将其发送到EntityFramework之前将其转换为字符串:

string stateCode = ((char)ClassX.eStateCode.Running).ToString();
.............
s => s.WFStateCode == stateCode

更新资料

您可以更改模型并将WFStateCode类型设置为eStateCode 这样,您将不需要任何转换。 EntityFramework支持EF5中的枚举。 您的最终代码应类似于:

s => s.WFStateCode == ClassX.eStateCode.Running

可以定义一个可以在lambda表达式中用作文字的方法,因此它不会发送到SQL吗?

不,那不可能。

但是我可以建议您使用另一种方法来保留当前的设计,同时使您可以使用比以下方法更简洁的语法

s => s.WFStateCode == ((char)ClassX.eStateCode.Running).ToString())

在每个enum声明另一个带有静态只读字段的静态类,该字段包含enum成员的字符串代码。 像这样:

public enum eStateCode
{
    Running = 'R',
    Terminated = 'T',
    Cancelled = 'C',
}

public static class DbStateCode
{
    public static readonly string Running = ((char)eStateCode.Running).ToString();
    public static readonly string Terminated = ((char)eStateCode.Terminated).ToString();
    public static readonly string Cancelled = ((char)eStateCode.Cancelled).ToString();
}

是的,这需要一些额外的努力。 但这是一次努力,一旦您只有几个这样的枚举,我认为就足够了。 因为这样您可以简单地使用:

s => s.WFStateCode == ClassX.DbStateCode.Running

不幸的是,这是实体框架的众多不足之一。 如果您的列是SQL Server中的char(1)或nchar(1),则EF 应该能够将其映射到char属性,因此您的语句可以是:

s => s.WFStateCode == (char)ClassX.eStateCode.Running

但是,不支持此功能。 解决方法:

使您的列成为整数。

alter table [YourTable] add [WFStateId] int not null default 1
update [YourTable] set [WFStateId] = case([WFStateCode])
when 'R' then 1
when 'T' then 2
else 3 end

我知道这会使在数据库上运行select的人阅读起来更加困难,但这可以通过创建一个新表来加入来减轻:

create table [WFState](
[Id] int not null identity primary key,
[Name] nvarchar(30) not null)
insert [WFState] values
('Running'),
('Terminated'),
('Cancelled')

为了保持良好的数据库设计实践,请添加外键:

alter table [YourTable] add constraint [FK_YourTable_WFState] foreign key([WFStateId]) references WFState([Id])

然后,您可以愉快地更改“ WFStateCode”属性,使其类型为ClassX.eStateCode并更改您的枚举定义:

public enum eStateCode
{
    Running = 1,
    Terminated = 2,
    Cancelled = 3,
}

现在,您可以像这样自由查询它:

s => s.WFStateCode == ClassX.eStateCode.Running

我了解这不能回答您有关将字符串字段映射到枚举的问题,但是此解决方法将通过两种方式改善您的系统:

1:取消魔术字符串反模式(如果用户不知道'R'表示正在运行,该怎么办?)

2:将完整性添加到您的数据库。 现在,没有人可以通过为表分配无效状态来破坏系统,例如EG set [WFStatusCode] = 'X'

暂无
暂无

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

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