Как сравнить дату в структуре сущностей, чтобы избежать ошибок округления?

У меня есть значение .NET DateTime, которое я записываю в поле «datetime» базы данных SQL Server (и, поверьте мне, я ЖЕЛАТЕЛЬНО, мы просто использовали «datetime2 (7)», которое точно соответствует точности DateTime .NET, но это не так) .

В любом случае, я записываю объект в базу данных, и это конкретное поле оказывается «2016-03-03 08: 55: 19.560».

Это время последней обработки, и я ищу другие записи, которые были обработаны до этого времени. Когда я запускаю предложение where фреймворка сущности, он завершает выполнение оператора, заканчивающегося на «@ p__linq__0 = '2016-03-03 08: 55: 19.5602354'» в качестве значения, с которым он сравнивает, которое в итоге оказывается немного больше, хотя эти два значения происходят из одного и того же экземпляра DateTime.

Я попытался изменить время сравнения с SqlDateTime, но тогда лямбда не компилируется, потому что не может сравнить DateTime? в SqlDateTime. В SqlDateTime есть методы сравнения, но я не знаю, распознает ли структура сущности эти функции.

Я даже не могу выполнить преобразование между ними в структуре сущностей, что просто дает ошибку «Невозможно преобразовать тип System.DateTime в тип System.Data.SqlTypes.SqlDateTime». LINQ to Entities поддерживает только преобразование примитива EDM или перечислимые типы ".


person Triynko    schedule 03.03.2016    source источник
comment
Какая требуемая точность времени - с точностью до секунды? сантисекунда? миллисекунда?   -  person Peter Smith    schedule 03.03.2016
comment
Требуемой точности нет. Дело в том, что если у меня есть модель со свойством DateTime с именем Fred, она записывается в поле базы данных типа «datetime», которое менее точно и усекается. Если я затем запущу linq-запрос, используя то же свойство Fred, и сравню его с тем же полем, в которое он был записан ... entity framework заполнит параметр запроса строковым представлением даты, имеющей больше цифр точности, чем то, что она написал в поле, поэтому сравнение с самим собой всегда не удается.   -  person Triynko    schedule 03.03.2016
comment
При проведении сравнения я смог исправить это, приведя значение сначала к SqlDateTime, а затем обратно к DateTime. Кажется, это усекает его так же, как и сравнение успешно, но я не уверен, насколько оно надежно.   -  person Triynko    schedule 03.03.2016


Ответы (1)


У меня такая же проблема. В моем случае я, наконец, оцениваю поля DateTime, используя:

public static DateTime RoundedToMs(this DateTime dt) {
    return new DateTime(dt.Ticks - (dt.Ticks % TimeSpan.TicksPerMillisecond), dt.Kind);
}

public static DateTime RoundedToMsForSql(this DateTime dt) {
    DateTime n = dt.RoundedToMs();            
    return new DateTime(n.Year, n.Month, n.Day, n.Hour, n.Minute, n.Second, (n.Millisecond / 10) * 10);
}

А в бизнес-коде:

someEntity.SomeDate = dateValue.RoundedToMsForSql();

В моем случае дело в том, что sql datetime имеет точность 3 мс, поэтому я решил удалить миллисекунды.

То же расширение может использоваться в запросах, фактически для заполнения переменных, используемых в запросах.

var d = DateTime.Now.RoundedToMsForSql();
var q = from e in ctx.Entities where e.SomeDate <= d;
person tschmit007    schedule 03.03.2016
comment
Это классно. В итоге я просто сделал это: var truncatedDate= (DateTime)(SqlDateTime)originalDate;, и, похоже, это сработало. Я даже пошел дальше и просто вычел целую секунду в моем конкретном случае, потому что значение - это время последней обработки, которое я бы никогда не хотел обрабатывать чаще, чем один раз в секунду (это должно быть каждые 30 минут), поэтому отбросить его на целую секунду даже безопаснее, чем отбросить на оставшиеся миллисекунды. - person Triynko; 03.03.2016
comment
У меня было такое же требование / парадигма, как и у вас: дата последнего редактирования. Я предпочитаю использовать максимальную точность, потому что: нулевой вероятности не существует :) (о проблеме меньше, позже). - person tschmit007; 04.03.2016