EF 代码生成:如何让系统枚举作为 EdmEnumType 工作?

Posted

技术标签:

【中文标题】EF 代码生成:如何让系统枚举作为 EdmEnumType 工作?【英文标题】:EF code generation: How to get a System enum to work as an EdmEnumType? 【发布时间】:2015-05-26 06:04:11 【问题描述】:

我正在尝试编写自己的代码生成模板来模仿 Visual Studio 附带的 Legacy ObjectContext 模板。已经跳了好几圈;现在我已经无法再与之前的代码调和了。

我有一个表格,其中一个字段代表System.DayOfWeek。但是由于我采用了“数据库优先”的方法,因此我无法将字段定义为该类型;相反,我必须定义自己的枚举类型并将其链接到System.DayOfWeek

现在我像这样设置我的字段类型:

这在旧的 ObjectContext 模板下运行良好,因为它生成了这个:

[EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=false)]
[DataMemberAttribute()]
public DayOfWeek DayOfWeek

    get
    
        return _DayOfWeek;
    
    set
    
        OnDayOfWeekChanging(value);
        ReportPropertyChanging("DayOfWeek");
        _DayOfWeek = (DayOfWeek)StructuralObject.SetValidValue((int)value, "DayOfWeek");
        ReportPropertyChanged("DayOfWeek");
        OnDayOfWeekChanged();
    

private DayOfWeek _DayOfWeek;
partial void OnDayOfWeekChanging(DayOfWeek value);
partial void OnDayOfWeekChanged();

但缺点是在我的整个代码中,我必须在 System.DayOfWeekSchoolManagement.BL.DayOfWeek 之间进行显式转换。

现在我很兴奋,因为我的新代码模板直接将其生成为 System.DayOfWeek,因此我不需要进行任何更显式的转换:

[EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=false)]
[DataMemberAttribute()]
public System.DayOfWeek DayOfWeek

    get
    
        return _dayOfWeek;
    
    set
    
        if (_dayOfWeek != value)
        
            OnDayOfWeekChanging(value);
            ReportPropertyChanging("DayOfWeek");
            _dayOfWeek = (System.DayOfWeek)StructuralObject.SetValidValue((System.Int32)value, "DayOfWeek");
            ReportPropertyChanged("DayOfWeek");
            OnDayOfWeekChanged();
        
    

private System.DayOfWeek _dayOfWeek;

但由于某种原因,在运行时,我一创建数据上下文,就会得到一个MetadataException

指定的架构无效。错误:

类型“SchoolManagement.BL.A2_SchoolHours”上的属性“DayOfWeek”使用 EdmScalarPropertyAttribute 进行属性化,但返回类型“System.DayOfWeek”,它不是原始类型或可识别的枚举类型。

呃……什么? System.DayOfWeek 不是公认的枚举类型?所以让我们比较一下另一个自定义枚举,只是代码中的几行,它不会引起对元数据的任何抱怨:

[EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=false)]
[DataMemberAttribute()]
public Grade Grade

    get
    
        return _grade;
    
    set
    
        if (_grade != value)
        
            OnGradeChanging(value);
            ReportPropertyChanging("Grade");
            _grade = (Grade)StructuralObject.SetValidValue((System.Byte)value, "Grade");
            ReportPropertyChanged("Grade");
            OnGradeChanged();
        
    

private Grade _grade;

Grade枚举的定义中,有一个装饰器:

[EdmEnumType(NamespaceName = "SchoolManagement.BL", Name = "Grade")]
[DataContract]
public enum Grade : byte

我猜EdmEnumType 是它起作用的原因。那么如何才能将其应用于System.DayOfWeek

【问题讨论】:

如果您要创建一个包含具有DayOfWeek 属性的类的小型代码优先项目,也许这会告诉您应该如何构建代码...... @SimonMᶜKenzie,代码优先不需要所有这些把我搞砸的装饰器。但是 DB First 代码生成工具确实会生成它们,我不能没有它们。 @ShaulBehr 为什么不尝试使用“DbContext”而不是“ObjectContext”? 【参考方案1】:

您遇到了实体框架的限制:http://connect.microsoft.com/visualstudio/feedback/details/739409/adding-enum。

如果您更改代码生成模板,您的方法将起作用:使用 DbContext 而不是 ObjectContext。

如果你想继续使用 ObjectContext,你应该实现以下更改:

1) 将枚举的定义移动到带有 ObjectContext 后代的程序集

2) 放入 EdmEnumType 属性(并设置 Name 和 NamespaceName 的值)

3) 如果需要,请指定 DataContract 和 EnumMember 属性 序列化/反序列化

namespace Model 
  [System.Data.Objects.DataClasses.EdmEnumTypeAttribute(Name = "Enum1", NamespaceName = "Model")]
  [System.Runtime.Serialization.DataContract()]
  public enum Enum1 
    [System.Runtime.Serialization.EnumMember()]
    a,
    [System.Runtime.Serialization.EnumMember()]
    b
  ;

【讨论】:

【参考方案2】:

如果您要基于现有枚举定义 EF 枚举,则不需要定义枚举值。

尝试从“编辑枚举类型”对话框中删除它们。

【讨论】:

嗯,是的,这是真的,但这与问题无关。我应该如何生成此属性,以便 EF 不会抱怨无效架构?

以上是关于EF 代码生成:如何让系统枚举作为 EdmEnumType 工作?的主要内容,如果未能解决你的问题,请参考以下文章

如何在EF6 Code First中创建与枚举对应的表?

如何使用 EF 5 存储枚举列表

如何在 .net 核心上使用 ef 核心在 postgresql(db first)中映射枚举

.Net开源数据库设计工具Mr.E For Linq (EF 6.1) 教程枚举类型的字段

如何使用 MongoDB 作为唯一/枚举存储

如何让vs2017 EF实体生成支持Mysql 和 Oracle?