LinqToDB 如何将枚举存储为字符串值?

LinqToDB how to store enum as string value?

LinqToDB 能否将枚举的值 属性 存储为枚举的字符串值而不是整数值?

public enum OrderType
{
    New,
    Cancel
}

[Table("Orders")]
public class Order
{
    [PrimaryKey, Identity]
    public int OrderId { get; set; }

    [Column]
    public OrderType Type { get; set; }
}

如何让 LinqToDB 将 "New" 或 "Cancel" 而不是 0 或 1 存储到数据库?

更新: LinqToDB 的答案似乎是在枚举上设置 MapValue 属性。我一直试图找到在数据对象上指定它的位置。

public enum OrderType
{
    [LinqToDB.Mapping.MapValue(Value = "NEW")]
    New,
    [LinqToDB.Mapping.MapValue(Value = "CANCEL")]
    Cancel
}

这会将枚举中的指定值作为文本存储在数据库中。

您可能已经考虑过使用包装器类型来促进与枚举之间的转换,但为了以防万一,还是这样做吧。

包装器允许您无法在枚举上定义的隐式转换

您可以实现一个允许一些非常有用的隐式转换的包装器(您不能对枚举类型本身执行此操作)。你可以将 Column 类型作为你的包装类型,但在数据库中它可以存储为字符串,因为它隐式转换为字符串类型,并作为字符串类型检索,但作为你的包装类型返回,同样是因为隐式转换。

用enum的地方都可以用

此外,因为它具有隐式转换,所以您的包装类型可以代表代码中使用枚举类型的任何地方。

演示

下面是此类包装器类型的演示,以及它无缝启用的炫酷转换:

using System;

namespace ConsoleApplication
{
    public static class Program
    {
        public enum OrderType
        {
            typeA,
            typeB
        }

        public class OrderTypeWrapper
        {
            private OrderType enumValue;

            public static implicit operator OrderType(OrderTypeWrapper wrapper)
            {
                return wrapper.EnumValue;
            }

            public static implicit operator OrderTypeWrapper(OrderType ot)
            {
                var wrapper = new OrderTypeWrapper();
                wrapper.EnumValue = ot;
                return wrapper;
            }

            public static implicit operator OrderTypeWrapper(String orderTypeValue)
            {
                var wrapper = new OrderTypeWrapper();
                wrapper.StringValue = orderTypeValue;
                return wrapper;
            }

            public static implicit operator String(OrderTypeWrapper wrapper)
            {
                return wrapper.StringValue;
            }

            public static implicit operator OrderTypeWrapper(int intValue)
            {
                var wrapper = new OrderTypeWrapper();
                wrapper.IntValue = intValue;
                return wrapper;
            }

            public static implicit operator int(OrderTypeWrapper wrapper)
            {
                return wrapper.IntValue;
            }

            public int IntValue
            {
                get
                {
                    return (int)enumValue;
                }
                set
                {
                    enumValue = (OrderType)value;
                }
            }
            public String StringValue
            {
                get
                {
                    return Enum.GetName(typeof(OrderType), enumValue);
                }
                set
                {
                    try
                    {
                        //Use TyeParse to do something other than throw exception in presence of bad string value.
                        //Perhaps set it to an "invalid" signifying value of the enum, instead.
                        enumValue = (OrderType)Enum.Parse(typeof(OrderType), value, true); //throws exception on bad value
                    }
                    catch (ArgumentException ae)
                    {
                        var message = String.Format("Attempt to make a bad string value of \"{0}\" into an OrderType. ", value);
                        throw new Exception(message, ae);
                    }
                }
            }
            public OrderType EnumValue
            {
                get
                {
                    return enumValue;
                }
                set
                {
                    enumValue = value; ;
                }
            }
        }

        public class Order
        {
            public OrderType TypeOfOrder { get; set;}
            public String StringValueOfAnOrderType { get; set; }

            public override String ToString()
            {
                return String.Format("TypeOfOrder={0}; StringValueOfAnOrderType={1}",TypeOfOrder,StringValueOfAnOrderType);
            }
        }

        public static void Main(string[] args)
        {
            Order order = new Order();
            Order order2 = new Order();
            Order order3 = new Order();

            //straight through, not that useful but shows that wrapper can stand in
            order.TypeOfOrder = (OrderTypeWrapper)OrderType.typeB;   
            //int to string name of the enum value                
            order.StringValueOfAnOrderType = (OrderTypeWrapper)1; 

            Console.WriteLine("order: " + order);

            //string to enum value, shows that case insensitive works, see third parameter of Parse.Enum to control this.
            order2.TypeOfOrder = (OrderTypeWrapper)"TYPEB";
            //enum value to string name of the enum value
            order2.StringValueOfAnOrderType = (OrderTypeWrapper)OrderType.typeB;  

            Console.WriteLine("order2: " + order2);

            //Not that helpful as you could also cast via (OrderType), but is shows that ints work, too.
            order3.TypeOfOrder = (OrderTypeWrapper)1;                   

            //Will helpfully blow up if the string type is wrong.
            try
            {
                order3.StringValueOfAnOrderType = (OrderTypeWrapper)"typeC";  
            }
            catch(Exception ex)
            {
                Console.WriteLine("Exception encountered: " + ex.Message);
            }

            Console.WriteLine("order3: " + order3);

            var key = Console.ReadKey();
        }
    }
}

为什么需要将这些值转换成字符串?你必须考虑你的数据库性能和大小来做这些事情。如果你想要简单的方法来做到这一点,你可以使用这样的东西:

public class Order
{
    [PrimaryKey, Identity]
    public int OrderId { get; set; }

    [Column]
    public OrderType Type { get; set; }

    private string _DisplayType;
    [NotMapped]
    public string DisplayType
    {
        get
        {
            if (Type != null)
                _DisplayType = Type.ToString();
            else
                _DisplayType = string.Empty;

            return _DisplayType;
        }
        set
        {
            if (_DisplayType != value)
            {
                _DisplayType = value;
            }
        }

    }
}

如果想在其他地方显示,可以绑定DisplayType。如果要更改数据库中的值,可以使用 Type 属性.

LinqToDB 的答案似乎是在枚举上设置 MapValue 属性。我一直试图找到在数据对象上指定它的位置。

public enum OrderType
{
    [LinqToDB.Mapping.MapValue(Value = "NEW")]
    New,
    [LinqToDB.Mapping.MapValue(Value = "CANCEL")]
    Cancel
}