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

5
LinqToDB能否将Enum属性的值存储为枚举的字符串值,而不是整数值?
public enum OrderType
{
    New,
    Cancel
}

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

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

我该如何让LinqToDB将“新建”或“取消”存储到数据库中,而不是0或1?

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

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

将指定的值以文本形式存储在数据库中。


为什么要将本来是数字值的值存储为字符串值? - Erik Philips
我认为他/她想要能够从数据库中查询数据并获得有意义的结果。最好在数据库中拥有一个表格来表示代码中的枚举,这样您就可以加入这些表格以获取查询的有意义数据,而且在其他地方使用时也可以提高性能。但是,当更改枚举值时,这将创建两个更新点的问题。 - bobwah
需要枚举的字符串值是因为我正在尝试将其与现有数据库一起使用,并考虑迁移离目前正在使用的Castle Activerecord。 - BiaachMonkie
你最终做了什么? - DWright
1
@DWright 我在问题中添加了一个更新,解决方案是在枚举上添加一个MapValue属性。 - BiaachMonkie
3个回答

9

看起来,对于LinqToDB的答案是在枚举上设置MapValue属性。我一直在尝试找到在数据对象上指定它的位置。

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

2
请参阅作者的文章使用MapValueAttribute控制Linq2db映射 - CodeFox

5

您可能已经考虑使用包装类型来简化枚举类型的转换,但是如果没有的话,请继续阅读。

包装类型允许您在枚举上不能定义的隐式转换

您可以实现一个包装类型,允许一些非常有用的隐式转换(在枚举类型本身上无法完成这些操作)。然后,您可以将Column类型设置为您的包装类型,在数据库中可以存储为字符串类型,因为它会隐式转换为字符串类型,并作为字符串类型检索,但由于隐式转换,它会作为包装类型返回。

它可以在任何使用枚举的地方使用

此外,由于它具有隐式转换,因此可以在代码中使用您的包装类型代替枚举类型。

演示

以下是这样一种包装类型及其所能无缝实现的炫酷转换的演示:

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();
        }
    }
}

0

为什么需要将这些值转换为字符串?您必须考虑数据库性能和大小来执行这些操作。如果您想要简单的方法,可以使用类似以下代码:

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属性。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接