Dapper And System.Data.OleDb DbType.Date, выбрасывающий 'OleDbException: несоответствие типов данных в выражении критериев' - PullRequest
3 голосов
/ 03 августа 2011

Не уверен, стоит ли мне поднимать вопрос по этому поводу, поэтому подумал, что я спрошу, знает ли кто-нибудь простой обходной путь для этого в первую очередь. Я получаю сообщение об ошибке при попытке использовать Dapper с OleDbConnection при использовании в сочетании с MS Access 2003 (Jet.4.0) (не мой выбор базы данных!)

При выполнении тестового кода ниже я получаю исключение «OleDbException: несоответствие типов данных в выражении критерия»

var count = 0;

using (var conn = new OleDbConnection(connString)) {

    conn.Open();
    var qry = conn.Query<TestTable>("select * from testtable where CreatedOn <= @CreatedOn;", new { CreatedOn = DateTime.Now });
    count = qry.Count();
}

Я полагаю, что из опыта работы с датами OleDb в прошлом можно сказать, что при установке значения DbType на Date он затем внутренне изменяет значение свойства OleDbType на OleDbTimeStamp вместо OleDbType.Date. Я понимаю, что это не из-за Даппера, а в том, что «можно» считать странным способом внутренних ссылок в классе OleDbParameter

При работе с другими ORM, необработанными ADO или моими собственными объектами фабрики я бы очистил объект команды непосредственно перед запуском команды и изменил бы OleDbType на Date.

Это невозможно с Dapper, насколько я вижу, поскольку объект команды кажется внутренним. К сожалению, у меня не было времени, чтобы изучить материал динамической генерации, поэтому я мог упустить что-то простое или я мог бы предложить исправить и внести свой вклад, а не просто поднять проблему.

Есть мысли?

Lee

1 Ответ

4 голосов
/ 27 августа 2015

Это старый поток, но у меня была та же проблема: Access не любит DateTime с миллисекундами, поэтому вы должны добавить и метод расширения, как это:

public static DateTime Floor(this DateTime date, TimeSpan span)
{
    long ticks = date.Ticks / span.Ticks;
    return new DateTime(ticks * span.Ticks, date.Kind);
}

И использовать его при передаче параметров:

var qry = conn.Query<TestTable>("select * from testtable where CreatedOn <= @CreatedOn;", new { CreatedOn = DateTime.Now.Floor(TimeSpan.FromSeconds(1)) });

К сожалению, в текущей версии Dapper (1.42) мы не можем добавить пользовательский TypeHandler для базовых типов (см. # 206 ).

Если вы можете изменить Dapper (используйте файл cs, а не DLL), объедините этот запрос на получение , и тогда вам не нужно будет использовать Floor для каждого параметра:

public class DateTimeTypeHandler : SqlMapper.TypeHandler<DateTime>
{
    public override DateTime Parse(object value)
    {
        if (value == null || value is DBNull) 
        { 
            return default(DateTime); 
        }
        return (DateTime)value;
    }

    public override void SetValue(IDbDataParameter parameter, DateTime value)
    {
        parameter.DbType = DbType.DateTime;
        parameter.Value = value.Floor(TimeSpan.FromSeconds(1));
    }
}

SqlMapper.AddTypeHandler<DateTime>(new DateTimeTypeHandler());
...