【问题标题】:LinqToDB how to store enum as string value?LinqToDB 如何将枚举存储为字符串值?
【发布时间】:2015-06-19 12:39:04
【问题描述】:

LinqToDB 能否将 Enum 属性的值存储为 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
}

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

【问题讨论】:

  • 为什么要将一个自然是数值的值存储为字符串值?
  • 我认为他/她希望能够从数据库中查询数据并获得有意义的结果。最好在数据库中有一个表来表示您在代码中拥有的枚举。然后,您可以加入这些以获取有意义的查询数据,以及在其他地方不使用它们的性能。但是,这将产生一个问题,即在更改枚举值时需要更新两个点。
  • 需要枚举字符串值的原因是因为我正在尝试将它与现有数据库一起使用,考虑从当前正在使用的 Castle Activerecord 迁移的选项。
  • 你最后做了什么?
  • @DWright 我对问题添加了更新,解决方案是在枚举上添加 MapValue 属性。

标签: c# string enums linq2db


【解决方案1】:

您可能已经考虑使用包装器类型来促进与枚举之间的转换,但以防万一。

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

你可以实现一个允许一些非常有用的隐式转换的包装器(你不能在枚举类型本身上做)。您可以将 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();
        }
    }
}

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

      【解决方案3】:

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

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

      【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-11-02
      • 2016-03-06
      • 1970-01-01
      • 1970-01-01
      • 2018-05-23
      • 1970-01-01
      • 2023-04-09
      相关资源
      最近更新 更多