我有一个'模型',我正在尝试将查询结果映射到,但由于某种原因它仍然失败。以下是一些更多信息:
此处发生异常(除了查询的选择部分之外的所有部分在现实生活中都不同):
var query = @"
SELECT
Id,
PublicationDate,
Title,
IntroText,
BodyText,
IsReadByTarget,
IsRequired
FROM Notifications
WHERE
CategoryId = @categoryId
";
var parameters = new Dictionary<string, object> {
{ "@categoryId", AppSettings.NotificationCategoryId },
};
var notifications = SqlHelper.GetList<Notification>(_connectionString, query, parameters);
SqlHelper是一个小助手类,可以完成所有映射。通知是我要映射到的模型。这就是它的样子:
public class Notification
{
public string Id { get; set; }
public Time PublicationDate { get; set; }
public string Title { get; set; }
public string IntroText { get; set; }
public string BodyText { get; set; }
public string ActiveText
{
get
{
return string.IsNullOrEmpty(IntroText) ? BodyText : IntroText;
}
}
public Notifiable Target { get; set; }
public bool IsReadByTarget { get; set; }
public bool IsRequired { get; set; }
}
时间也是一个自定义类。它基本上保持日期+时间(就像日期时间,但更小)。它仅用于通信而非计算或其他:
public class Time
{
public int Year { get; set; }
public int Month { get; set; }
public int Day { get; set; }
public int Hour { get; set; }
public int Minute { get; set; }
public int Second { get; set; }
public Time()
: this(DateTime.Now)
{
}
public Time(DateTime time)
{
Year = time.Year;
Month = time.Month;
Day = time.Day;
Hour = time.Hour;
Minute = time.Minute;
Second = time.Second;
}
public static implicit operator DateTime(Time time)
{
return new DateTime(time.Year, time.Month, time.Day, time.Hour, time.Minute, time.Second);
}
public static implicit operator Time(DateTime dateTime)
{
return new Time(dateTime);
}
}
所以这也是魔术开始的地方。如您所见,它应该默默地从DateTime转换为Time,从Time转换为DateTime。这在正常情况下工作正常。所以做一些像......
Time myTime = DateTime.Now;
......工作正常。
但就我而言,我得到了:
从'System.DateTime'到'MyNamespace.Time'的无效演员。
public static List<T> GetList<T>(string connectionString, string query, Dictionary<string, object> parameters) where T : class, new()
{
var data = new List<T>();
using (var conn = new SqlConnection(connectionString))
{
conn.Open();
using (var command = conn.CreateCommand())
{
command.CommandText = query;
if (parameters != null)
{
foreach (var parameter in parameters)
{
command.Parameters.AddWithValue(parameter.Key, parameter.Value);
}
}
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
var item = Read<T>(reader);
data.Add(item);
}
}
}
}
return data;
}
public static T Read<T>(SqlDataReader reader) where T : new()
{
var item = new T();
var properties = typeof(T).GetProperties();
foreach (var propertyInfo in properties)
{
if (!reader.HasColumn(propertyInfo.Name)) continue;
var ordinal = reader.GetOrdinal(propertyInfo.Name);
if (reader.IsDBNull(ordinal)) continue;
propertyInfo.SetValue(item, Convert.ChangeType(reader[ordinal], propertyInfo.PropertyType), null);
}
return item;
}
基本上,将DateTime列映射到Time对象时将其映射到DateTime对象时运行正常。 任何有关为什么会发生这种情况以及合理修复的帮助都会受到赞赏。
我知道我可以创建一个新模型,它使用DateTime代替Time并映射到该模型,然后将该模型映射到带有Time的模型,但这不是一个合理的修复。
答案 0 :(得分:4)
我建议您创建自定义转化词典:
private static readonly Dictionary<Tuple<Type, Type>, Func<object, object>>
Mappings = new Dictionary<Tuple<Type, Type>, Func<object, object>>
{
{ Tuple.Create(typeof(DateTime), typeof(Time)), x => (Time)(DateTime) x },
// Any other conversions...
};
然后:
object originalValue = reader[ordinal];
Func<object, object> converter;
if (!Mappings.TryGetValue(Tuple.Create(originalValue.GetType(),
propertyInfo.PropertyType),
out converter)
{
// Fall back to Convert.ChangeType
converter = x => Convert.ChangeType(x, propertyInfo.PropertyType);
}
object targetValue = converter(originalValue);
propertyInfo.SetValue(item, targetValue, null);