我正在使用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)
会帮我解决这个问题。
有没有人?帮助总是值得赞赏的。
答案 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