设计支持 HeadSprings 枚举的自定义 PetaPoco 映射器 Class

Designing a custom PetaPoco mapper that supports HeadSprings Enumeration Class

我正在尝试创建一个映射器,以便 PetaPoco 可以使用 枚举 class 属性来混合和持久化 POCO。查看更多关于枚举 classes here or here.

例如,就拿这个class。

    public class PetType : Headspring.Enumeration<PetType>
    {
       public static readonly PetType Frog = new PetType(1, "Frog");
       public static readonly PetType Cat = new PetType(2, "Cat");
       public static readonly PetType Fish = new PetType(3, "Fish");
       public static readonly PetType Dog = new PetType(4, "Dog");

       private PetType(int value, string displayName) : base(value, displayName) { }
     }

可以这样使用:

var MyPet = PetType.Dog;

这是我想要 hydrate/persist 与数据库的 Poco:

    public class Pet
    {
         public int ID { get; set; }
         public string OwnerName { get; set; }
         public DateTime DateOfBirth { get; set; }
         public string PetName{ get; set; }
         public PetType PetType{ get; set; }
    }

我设计了一个可与 PetType 一起使用的自定义映射器:

    class EnumClassMapper :  PetaPoco.StandardMapper 
    {
       public override Func<object, object> GetFromDbConverter(System.Reflection.PropertyInfo targetProperty, Type sourceType)
       {
           if (targetProperty.PropertyType == typeof(PetType))
           {
               return (x) => PetType.FromValue((int) x);
           }
           return base.GetFromDbConverter(targetProperty, sourceType);
       }

       public override Func<object, object> GetToDbConverter(System.Reflection.PropertyInfo sourceProperty)
       {
           if (sourceProperty.PropertyType == typeof(PetType))
           {
               return (x) => ((PetType)x).Value;
           }
           return base.GetToDbConverter(sourceProperty);
       }
   }

但是假设我创建另一个枚举子class用于配置。

    public class Disposition: Headspring.Enumeration<Disposition>
    {
       public static readonly Friendly = new Disposition(1, "Friendly");
       public static readonly Timid = new Disposition(2, "Timid");
       public static readonly Aggressive = new Disposition(3, "Aggressive");

       private Disposition(int value, string displayName) : base(value, displayName) { }
     }

我不想每次创建枚举 class 的新子 class 时都必须更新我的映射器。我更喜欢映射代码可以识别 属性 类型是枚举 class 的后代,并相应地进行映射。我认为答案是利用反射,但我不知道如何进行。

怎么样

public class EnumClassMapper<T> :  PetaPoco.StandardMapper 
    where T : Headspring.Enumeration<T>   
{
   public override Func<object, object> GetFromDbConverter(System.Reflection.PropertyInfo targetProperty, Type sourceType)
   {
       return (x) => Enumeration<T, int>.FromValue((int) x);
   }

   public override Func<object, object> GetToDbConverter(System.Reflection.PropertyInfo sourceProperty)
   {
       return (x) => ((T)x).Value;
   }
}

var builder = DatabaseConfiguration.Build()
    .UsingConnectionStringName("sqlite")
    .UsingDefaultMapper<ConventionMapper>(m =>
    {
        m.FromDbConverter = (targetProperty, sourceType) =>
        {
            if (targetProperty == null)
                return null;

            var t = targetProperty.PropertyType;

                    if (t.BaseType == null || ! t.BaseType.IsGenericType) 
                        return null;

                    if (t.BaseType.GetGenericTypeDefinition() != typeof(Headspring.Enumeration<>))
                        return null;

                    return ((IMapper)Activator.CreateInstance(typeof(EnumClassMapper<>).MakeGenericType(t))).GetFromDbConverter(targetProperty, sourceType);
        };
        m.ToDbConverter = sourceProperty =>
        {
            if (sourceProperty == null)
                return null;

            var t = sourceProperty.PropertyType;

                    if (t.BaseType == null || !t.BaseType.IsGenericType)
                        return null;

                    if (t.BaseType.GetGenericTypeDefinition() != typeof(Headspring.Enumeration<>))
                        return null;

                    return ((IMapper)Activator.CreateInstance(typeof(EnumClassMapper<>).MakeGenericType(t))).GetToDbConverter(sourceProperty);
        };
    });

var db = builder.Create();