0

我有一个“模型”,我试图将查询结果映射到,但由于某种原因它一直失败。这是更多信息:

异常发生在这里(除了查询的选择部分在现实生活中是不同的):

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 的模型,但这不是一个合理的解决方法。

4

1 回答 1

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);
于 2012-12-27T08:54:03.607 回答