[英]Seamless way to store and retrieve enums from a string field using EF Model
I have several enums, that represent states, and all correspond to string fields on the EF model. 我有几个代表状态的枚举,它们都对应于EF模型上的字符串字段。 All enums values are chosen so they can be easily represented as chars, so they are set like this:
选择所有枚举值,以便可以轻松地将它们表示为char,因此将它们设置如下:
public enum eStateCode
{
Running = 'R',
Terminated = 'T',
Cancelled = 'C',
}
This way database field can be a char[1] type, capable of storing meaning codes, instead a abstract numeric field. 这样,数据库字段可以是char [1]类型,能够存储含义代码,而不是抽象的数字字段。 This approach works seamless using Linq to SQL, because char SQL columns are mapped to char fields, but not using EF.
该方法使用Linq to SQL无缝运行,因为char SQL列映射到char字段,但不使用EF。
Using EF, when i try to use it on a lambda expression like this 使用EF,当我尝试在这样的lambda表达式上使用它时
s => s.WFStateCode == ((char)ClassX.eStateCode.Running).ToString())
i get the 我得到了
LINQ to Entities does not recognize the method
LINQ to Entities无法识别该方法
error, meaning that ((char)ClassX.eStateCode.Running).ToString()
was sent to SQL. 错误,表示
((char)ClassX.eStateCode.Running).ToString()
已发送到SQL。
I can circumvent the problem by putting put ((char)ClassX.eStateCode.Running).ToString()
in a variable but makes the code much more verbose. 我可以通过将put
((char)ClassX.eStateCode.Running).ToString()
放在变量中来解决问题,但是会使代码更加冗长。 I read several posts but none say how I can force EF to resolve the part of expression on the client side. 我读了几篇文章,但没有人说我如何强迫EF在客户端解析表达式的一部分。
It is possible to define a method that can be used in a lambda expression as a literal, so it will not be sent to SQL? 可以定义一个可以在lambda表达式中用作文字的方法,因此它不会发送到SQL吗?
The error means that EntityFramework cannot translate your code into SQL. 该错误意味着EntityFramework无法将您的代码转换为SQL。 You can convert it to string before sending to EntityFramework:
您可以在将其发送到EntityFramework之前将其转换为字符串:
string stateCode = ((char)ClassX.eStateCode.Running).ToString();
.............
s => s.WFStateCode == stateCode
You can change your model and set type of WFStateCode
to eStateCode
. 您可以更改模型并将
WFStateCode
类型设置为eStateCode
。 By doing so, you will not need any conversion. 这样,您将不需要任何转换。 EntityFramework supports enums from EF5.
EntityFramework支持EF5中的枚举。 Your final code should be something like:
您的最终代码应类似于:
s => s.WFStateCode == ClassX.eStateCode.Running
It is possible to define a method that can be used in a lambda expression as a literal, so it will not be sent to SQL?
可以定义一个可以在lambda表达式中用作文字的方法,因此它不会发送到SQL吗?
No, that's not possible. 不,那不可能。
But I could suggest you another approach that would keep your current design and at the same time will allow you to use an even more concise syntax than 但是我可以建议您使用另一种方法来保留当前的设计,同时使您可以使用比以下方法更简洁的语法
s => s.WFStateCode == ((char)ClassX.eStateCode.Running).ToString())
Right after each enum
declare another static class with static readonly fields containing the string codes of the enum
members. 在每个
enum
声明另一个带有静态只读字段的静态类,该字段包含enum
成员的字符串代码。 Something like this: 像这样:
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();
}
Yes, that requires some additional effort. 是的,这需要一些额外的努力。 But it's one time effort and once you have just several enums like this I think it's worth enough.
但这是一次努力,一旦您只有几个这样的枚举,我认为就足够了。 Because then you can use simply:
因为这样您可以简单地使用:
s => s.WFStateCode == ClassX.DbStateCode.Running
Unfortunately, this is one of the many shortfalls of Entity Framework. 不幸的是,这是实体框架的众多不足之一。 If your column is char(1) or nchar(1) in SQL Server, EF should be able to map it to a char property, and therefore your statement could be:
如果您的列是SQL Server中的char(1)或nchar(1),则EF 应该能够将其映射到char属性,因此您的语句可以是:
s => s.WFStateCode == (char)ClassX.eStateCode.Running
However, this is not supported. 但是,不支持此功能。 Here is a work-around:
解决方法:
Make your column an integral type. 使您的列成为整数。
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
I know this makes it more difficult to read for someone running a select on the database, but this can be alleviated by creating a new table to join to: 我知道这会使在数据库上运行select的人阅读起来更加困难,但这可以通过创建一个新表来加入来减轻:
create table [WFState](
[Id] int not null identity primary key,
[Name] nvarchar(30) not null)
insert [WFState] values
('Running'),
('Terminated'),
('Cancelled')
To keep up good database design practices, add a foreign key: 为了保持良好的数据库设计实践,请添加外键:
alter table [YourTable] add constraint [FK_YourTable_WFState] foreign key([WFStateId]) references WFState([Id])
Then you can happily change your 'WFStateCode' property to make it type ClassX.eStateCode
and change your enum definition: 然后,您可以愉快地更改“ WFStateCode”属性,使其类型为
ClassX.eStateCode
并更改您的枚举定义:
public enum eStateCode
{
Running = 1,
Terminated = 2,
Cancelled = 3,
}
Now you will be able to freely query against it like this: 现在,您可以像这样自由查询它:
s => s.WFStateCode == ClassX.eStateCode.Running
I understand this does not answer your question about mapping a string field to enum, but this workaround will improve your system in two ways: 我了解这不能回答您有关将字符串字段映射到枚举的问题,但是此解决方法将通过两种方式改善您的系统:
1: Takes away the magic string anti-pattern (What if a user doesn't know that 'R' means running, etc.) 1:取消魔术字符串反模式(如果用户不知道'R'表示正在运行,该怎么办?)
2: Adds integrity to your database. 2:将完整性添加到您的数据库。 Now no one can break your system by assigning an invalid status to your table, EG
set [WFStatusCode] = 'X'
现在,没有人可以通过为表分配无效状态来破坏系统,例如EG
set [WFStatusCode] = 'X'
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.