用Dapper保湿枚举类

时间:2019-08-21 16:14:49

标签: c# dapper

我正在使用Dapper来充实C#类。我最近从字符串常量的集合移到了此处定义的“枚举类”:https://docs.microsoft.com/en-us/dotnet/architecture/microservices/microservice-ddd-cqrs-patterns/enumeration-classes-over-enum-types

我的枚举看起来像这样:

public abstract class Enumeration : IComparable
    {
        public string Name { get; }

        protected Enumeration(string name)
        {
            Name = name;
        }

        public static IEnumerable<T> GetAll<T>() where T : Enumeration
        {
            var fields = typeof(T).GetFields(BindingFlags.Public |
                                             BindingFlags.Static |
                                             BindingFlags.DeclaredOnly);

            return fields.Select(f => f.GetValue(null)).Cast<T>();
        }

        public static IEnumerable<T> ToSortedEnumerable<T>() where T : Enumeration
        {
            List<T> values = GetAll<T>().ToList();
            values.Sort();
            return values;
        }

        public int CompareTo(object other) =>
            string.Compare(Name, ((Enumeration) other).Name, StringComparison.Ordinal);

        public static implicit operator string(Enumeration enumeration)
        {
            return enumeration?.ToString();
        }

        public static bool operator ==(Enumeration e1, Enumeration e2)
        {
            return Equals(e1, e2);
        }

        public static bool operator !=(Enumeration e1, Enumeration e2)
        {
            return !Equals(e1, e2);
        }

        public static bool HasValue<T>(string valueToCheck) where T : Enumeration
        {
            return Enumeration.GetAll<T>().Any(x => x.Name.Equals(valueToCheck, StringComparison.OrdinalIgnoreCase));
        }

        public static bool TryGetEnumeration<T>(string valueToCheck, out T result) where T : Enumeration
        {
            result = Enumeration.GetAll<T>()
                                .FirstOrDefault(
                                    x => x.Name.Equals(valueToCheck, StringComparison.OrdinalIgnoreCase));

            return result != null;
        }

        public static T GetEnumeration<T>(string valueToCheck) where T : Enumeration
        {
            var result = Enumeration.GetAll<T>()
                                .FirstOrDefault(
                                    x => x.Name.Equals(valueToCheck, StringComparison.OrdinalIgnoreCase));

            if (result == null)
            {
                throw new ArgumentException($"Invalid {typeof(T).Name}: {valueToCheck}");
            }

            return result;
        }

        public override bool Equals(object obj)
        {
            var otherValue = obj as Enumeration;

            if (otherValue == null)
                return false;

            bool typeMatches = this.GetType() == obj.GetType();
            bool valueMatches = this.Name.Equals(otherValue.Name);

            return typeMatches && valueMatches;
        }

        public override int GetHashCode()
        {
            return 539060726 + EqualityComparer<string>.Default.GetHashCode(this.Name);
        }

        public override string ToString() => this.Name;
    }

我的Race类如下:

public class Race : Enumeration
    {
        public static Race White = new Race("White");
        public static Race Hawaiian = new Race("Native Hawaiian");
        public static Race Filipino = new Race("Filipino");
        public static Race Black = new Race("Black / African American");
        public static Race Chinese = new Race("Chinese");
        public static Race Japanese = new Race("Japanese");
        public static Race Korean = new Race("Korean");
        public static Race Vietnamese = new Race("Vietnamese");
        public static Race AsianIndian = new Race("Asian Indian");
        public static Race OtherAsian = new Race("Other Asian");
        public static Race Samoan = new Race("Samoan");
        public static Race AmericanIndian = new Race("American Indian");
        public static Race AlaskaNative = new Race("Alaska Native");
        public static Race Guamanian = new Race("Guamanian");
        public static Race Chamorro = new Race("Chamorro");
        public static Race OtherPacificIslander = new Race("Other Pacific Islander");
        public static Race Other = new Race("Other");

        public Race(string name) : base(name)
        { }
    }

我的简化Person对象看起来像这样:

public class Person
{
    public Person(Guid personId, Race race){
        PersonId = personId;
        Race = race;
    }
    public Race Race {get;}
    public Guid PersonId {get;}
}

这是一个简化的Dapper命令(与postgresql对话)可以正常工作(PersonId正确合并),但是Race始终为NULL。

return connection.Query<Person>(sql: @"
    SELECT person_id as PersonId
    ,race
    FROM public.people");

我尝试将SQL调整为此:

return connection.Query<Person>(sql: @"
    SELECT person_id as PersonId
    ,race as Name
    FROM public.people");

但这也会导致Race的值为空。

我正在尝试的可能吗?我需要为此做一个splitOn吗?我避免了这种情况,因为我的真实类具有许多此类属性,并且它们都必须是Name和。 。 。好吧,如果我在这里错过了一些愚蠢的事情,我就是不想去那里。老实说,我认为

public static implicit operator string(Enumeration enumeration)

会帮我解决这个问题。

有没有人?帮助总是值得赞赏的。

2 个答案:

答案 0 :(得分:0)

也许这太简单了,但是,您选择的列名需要与要映射到的类中的属性匹配,否则Dapper将不知道如何使映射匹配。

因此,如果您的课程是:

public class Person
{
    public Race Race {get;}
    public Guid PersonId {get;}
}

然后您的查询需要匹配:

return connection.Query<Person>(sql: @"
    SELECT 
        Race
       , person_id as PersonId
FROM public.people");

请注意Race中的大写R。 (而且,尽管不确定,我还是很喜欢将它们保持在相同的顺序。)

此外,如果您直接对数据库执行查询,是否还能获得预期的结果?

答案 1 :(得分:0)

好,知道了。两件事:

首先,splitOn是执行此操作的方法。一个不同但相关的最终版本如下:

return connection.Query<Program,
    AssistanceProgramCategory,
    AssistanceProgramType,
    AssistanceProgramLegalType,
    ProgramAuthority,
    Program>(sql: Constants.SqlStatements.SELECT_PROGRAMS_SQL,
    (program, category, programType, legalType, authority) =>
    {
        program.AssistanceCategory = category;
        program.ProgramType = programType;
        program.ProgramLegalType = legalType;
        program.Authority = authority;
        return program;
    }, splitOn: "Name,Jurisdiction");

其中AssistanceProgramCategory,AssistanceProgramType和AssistanceProgramLegalType都是Enumeration的子代。

第二,SQL确实必须使用Name来传递列,如:

SELECT global_id as GlobalId
,tier
,program_description as Name
,program_type as Name
,program_legal_type as Name
,jurisdiction as Jurisdiction
,customer_id as CustomerId
,program_name as ProgramNameForJurisdiction
,program_description as ProgramName
FROM public.assistance_programs

第三,我只需要在splitOn中放置一次“名称”-名称的每个实例都会导致创建一个新对象。

最后,我必须交换Jurisdiction和CustomerId,因为CustomerId可以为null,并且当NULL时,它不会将最终的混合发送到ProgramAuthority。管辖区始终存在,因此可以通过交换SQL中的列来解决问题。

希望这对某人有帮助。

祝一切顺利,

V