EF 4.1 Code First - 将枚举包装器映射为复杂类型

Nat*_*ock 15 .net entity-framework ef-code-first entity-framework-4.1

我正在尝试使用EF 4.1构建枚举问题的通用解决方案.我的解决方案基本上是如何在ef 4中伪造枚举的通用版本.枚举包装类在其余代码中运行得非常好,并允许以下代码:

EnumWrapper<Color> c = Color.Red;
Run Code Online (Sandbox Code Playgroud)

这是枚举包装类:

public class EnumWrapper<TEnum> where TEnum : struct, IConvertible
{
    public EnumWrapper()
    {
        if (!typeof(TEnum).IsEnum)
            throw new ArgumentException("Not an enum");
    }

    public TEnum Enum { get; set; }

    public int Value
    {
        get { return Convert.ToInt32(Enum); }
        set { Enum = (TEnum)(object)value; }
    }

    public static implicit operator TEnum(EnumWrapper<TEnum> w)
    {
        if (w == null) return default(TEnum);
        else return w.Enum;
    }

    public static implicit operator EnumWrapper<TEnum>(TEnum e)
    {
        return new EnumWrapper<TEnum>() { Enum = e };
    }

    public static implicit operator int(EnumWrapper<TEnum> w)
    {
        if (w == null)
            return Convert.ToInt32(default(TEnum));
        else
            return w.Value;
    }
}
Run Code Online (Sandbox Code Playgroud)

枚举:

public enum Color { red = 1, green = 2, blue = 3 }
Run Code Online (Sandbox Code Playgroud)

POCO:

public class ChickenSandwich 
{
    public ChickenSandwich() {
        CheeseColor = new EnumWrapper<Color>();
    }

    public int ID { get; set; }
    public string Name { get; set; }
    public EnumWrapper<Color> CheeseColor { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

制图:

public class ColorMapping : ComplexTypeConfiguration<EnumWrapper<Color>> 
{
    public ColorMapping() {
        Ignore(x => x.Enum);
        Property(x => x.Value);
    }
}
Run Code Online (Sandbox Code Playgroud)

我也尝试将它映射到ChickenSandwich的EntityTypeConfiguration,如下所示:

Property(x => x.CheeseColor.Value).HasColumnName("CheeseColor");
Run Code Online (Sandbox Code Playgroud)

如果我将它留给ColorMapping并且没有对ChickenSandwichMapping进行显式映射,那么它就不会将它放在数据库中.如果我将它映射到x.CheeseColor.Value方式,我会得到可怕的:

System.InvalidOperationException:配置的属性'CheeseColor'不是实体'ChickenSandwich'上的声明属性.验证它是否未从模型中明确排除,并且它是有效的原始属性.


编辑

我无法获得enum包装器的通用版本,所以我已经编写了单独的包装器.这不完全是我想要的,因为它违反了DRY原则,但它确实允许我将列查询为枚举.

[ComplexType]
public class ColorWrapper
{
    [NotMapped]
    public Color Enum { get; set; }

    public int Value
    {
        get { return (int)Enum; }
        set { Enum = (Color)value; }
    }

    public static implicit operator Color(ColorWrapper w)
    {
        if (w == null) return default(Color);

        return w.Enum;
    }

    public static implicit operator ColorWrapper(Color c)
    {
        return new ColorWrapper { Enum = c };
    }
}
Run Code Online (Sandbox Code Playgroud)

我不得不在ChickenSandwich类上使用ColorWrapper.它或多或少地透明地工作.然后必须将它添加到我的映射类构造函数以获取我想要的列名称:

Property(x => x.CheeseColor.Value).HasColumnName("CheeseColorId");
Run Code Online (Sandbox Code Playgroud)

Ser*_*eit 30

enums在EF 4中有一种更简单的映射方法:只需intChickenSandwich类上创建一个属性来表示枚举的int值.那是EF应该映射的属性,然后有一个"迷你包装"属性,允许你使用enum

public class ChickenSandwich 
{   
    public int ID { get; set; }
    public string Name { get; set; }

    // This property will be mapped
    public int CheeseColorValue { get; set; }

    public Color CheseColor
    {
        get { return (Color) CheeseColorValue; }
        set { CheeseColorValue = (int) value; }
    }
}
Run Code Online (Sandbox Code Playgroud)

我实际上不必使用Fluent API或任何类型的属性修饰来实现此功能.在生成数据库时,EF会很乐意忽略它不知道如何映射的任何类型,但该int属性将被映射.

我也尝试过enums基于那篇文章的映射,但它让我头疼不已.这种方法效果很好,你可以调整你的解决方案,使用你的包装器作为"映射"属性,即CheeseColor在这种情况下.

  • @Nathan - 这是正确的我害怕.在看到其他方法给我的所有麻烦后,我认为这是一个很小的代价.我必须说,在我的情况下,int/enum属性并不是我的`where`子句的重点. (3认同)

Hen*_*bæk 7

我通过简单地使它抽象并移动来获得Nathan通用枚举包装类的工作:

public static implicit operator EnumWrapper <TEnum> (TEnum e)
Run Code Online (Sandbox Code Playgroud)

这样的派生类:

public class CategorySortWrapper : EnumWrapper<CategorySort>
{
    public static implicit operator CategorySortWrapper(CategorySort e)
    {
        return new CategorySortWrapper() { Enum = e };
    }
}

public abstract class EnumWrapper<TEnum> where TEnum : struct, IConvertible
{
    public EnumWrapper()
    {
        if (!typeof(TEnum).IsEnum)
            throw new ArgumentException("Not an enum");
    }

    public TEnum Enum { get; set; }

    public int Value
    {
        get { return Convert.ToInt32(Enum); }
        set { Enum = (TEnum)(object)value; }
    }

    public static implicit operator int(EnumWrapper<TEnum> w)
    {
        if (w == null)
            return Convert.ToInt32(default(TEnum));
        else
            return w.Value;
    }
}
Run Code Online (Sandbox Code Playgroud)

在我的代码中我只是像这样使用它

public CategorySortWrapper ChildSortType { get; set; }

category.ChildSortType = CategorySort.AlphabeticOrder;
Run Code Online (Sandbox Code Playgroud)

我没有做任何其他事情,EF 4.1在名为ChildSortType_Value的数据库中创建了一个"ComplexType like field"