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

本文关键字:枚举 检索 方式 存储 模型 EF 字符串 字段 使用 | 更新日期: 2023-09-27 18:04:48

我有几个枚举,它们表示状态,并且都对应于EF模型上的字符串字段。所有枚举的值都被选择了,所以它们可以很容易地表示为字符,所以它们被设置为这样:

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到实体不能识别

方法

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

我可以通过将put ((char)ClassX.eStateCode.Running).ToString()放在一个变量中来规避这个问题,但这会使代码更加冗长。我读了几个帖子,但没有一个说我如何能迫使EF解决客户端表达的部分。

有可能定义一个方法,可以在lambda表达式中使用作为文字,所以它不会被发送到SQL?

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

该错误意味着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

不幸的是,这是实体框架的众多不足之一。如果你的列是char(1)或nchar(1)在SQL Server中,E.F. 应该能够映射到一个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,并改变你的enum定义:

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

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

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

我知道这并不能回答你关于将字符串字段映射到enum的问题,但是这个解决方法将从两个方面改善你的系统:

1:去掉了神奇的字符串反模式(如果用户不知道'R'意味着运行,等等)

2:增加数据库的完整性。现在没有人可以通过给你的表分配一个无效的状态来破坏你的系统,例如:set [WFStatusCode] = 'X'