簡體   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