因为公司业务的需要,系统对于时间的展示要有多元化的需求。这就要求DateTime类型要有DateTimeKind。
ORM我采用的是Dapper.Net,其原生态不支持DateTimeKind的指定。所以只能分析源代码进行修改。忙活了大半个晚上,终于解决了,记录一下。
第一步,当然是定义Attribute
/// <summary>
/// 表字段
/// </summary>
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
public class ColumnAttribute : Attribute
{
/// <summary>
/// 指定返回时间类型的DateTimeKind
/// </summary>
public DateTimeKind DateTimeKind { get; set; }
/// <summary>
///
/// </summary>
[TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
public ColumnAttribute()
{
}
}
第二步,在实体上打标签
public class User
{
[Column(DateTimeKind = DateTimeKind.Utc)]
public DateTime AddTime { get; set; }
}
第三步,将DateTime.SpecifyKind方法信息在Dapper.Net 的SqlMapper类中初始化
static MethodInfo specifyKind = typeof(DateTime).GetMethod("SpecifyKind", BindingFlags.Static | BindingFlags.Public);
最后一步,在SqlMapper 的GetTypeDeserializer方法中增加代码
if (specializedConstructor == null)
{
//Add by Arden 2013/10/17
//数据库返回时间 指定 DateTimeKind
if (item.MemberType == typeof(DateTime))
{
var entityInfo = EntityCache.GetEntityInfo(type);
var dateTimeAttr = entityInfo.GetPropertyInfo(item.Property.Name).ColumnAttribute;
if (dateTimeAttr != null && dateTimeAttr.DateTimeKind != DateTimeKind.Unspecified)
{
il.Emit(OpCodes.Ldc_I4_S, (byte)dateTimeAttr.DateTimeKind);
il.Emit(OpCodes.Call, specifyKind);
}
}
//Add End
// Store the value in the property/field
if (item.Property != null)
{
if (type.IsValueType)
{
il.Emit(OpCodes.Call, DefaultTypeMap.GetPropertySetter(item.Property, type)); // stack is now [target]
}
else
{
il.Emit(OpCodes.Callvirt, DefaultTypeMap.GetPropertySetter(item.Property, type)); // stack is now [target]
}
}
else
{
il.Emit(OpCodes.Stfld, item.Field); // stack is now [target]
}
}
结束。