Estoy tratando de construir una solución genérica al problema de las enumeraciones con EF 4.1. Mi solución es básicamente una versión genérica de How to fake enums in ef 4. La clase de enumeración envoltorio funciona de maravilla en el resto del código y permite código como:EF 4.1 Code First - map enum wrapper como tipo complejo
EnumWrapper<Color> c = Color.Red;
Aquí es la clase de enumeración envoltorio:
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;
}
}
enumeración:
public enum Color { red = 1, green = 2, blue = 3 }
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; }
}
Mapeo:
public class ColorMapping : ComplexTypeConfiguration<EnumWrapper<Color>>
{
public ColorMapping() {
Ignore(x => x.Enum);
Property(x => x.Value);
}
}
También he intentado mapear en EntityTypeConfiguration del ChickenSandwich así:
Property(x => x.CheeseColor.Value).HasColumnName("CheeseColor");
Si lo dejo hasta la asignación de color y hacer ninguna asignación explícita en la ChickenSandwichMapping, sólo doesn No lo pongas en la base de datos. Si me Mapa de la manera x.CheeseColor.Value, consigo la temida:
System.InvalidOperationException: La propiedad configurado 'CheeseColor' es no una propiedad declarada en la entidad 'ChickenSandwich'. Verificar que no ha sido explícitamente excluidos del modelo y que es válida una primitiva propiedad ..
Editar
yo no era capaz de obtener la versión genérica de la envoltura enum funcionando, así que me he ido con la redacción de envoltorios individuales. No es exactamente lo que quería porque infringe el principio DRY, pero me permite consultar la columna como una enumeración.
[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 };
}
}
Tuve que usar el ColorWrapper en la clase ChickenSandwich. Funciona de manera más o menos transparente. Entonces tuvo que añadir esto a mi constructor de la clase de mapeo para obtener el nombre de la columna que quería:
Property(x => x.CheeseColor.Value).HasColumnName("CheeseColorId");
¿No tendríamos que hacer consultas linq contra el valor int para que pueda consultar la base de datos subyacente? Es decir. no tendríamos que hacer "desde cs en ChickenSandwiches donde CheeseColorValue = (int) CheeseColor.Red" –
@Nathan - Eso es correcto, me temo. Lo vi como un pequeño precio a pagar después de todos los problemas que el otro método me dio. Debo decir que en mi caso las propiedades int/enum no han sido el foco de mis cláusulas 'where'. –
Terminé yendo con envoltorios individuales para cada enumeración. Es repetitivo, pero me permite consultar con enumeraciones, lo cual hacemos bastante en realidad. La aplicación real no es realmente sobre sandwiches de pollo. Es más como consultar una lista de clientes en función de si son empresas, personas, etc. –