Сравнение DateTime через LINQ запрос

310
09 июля 2017, 10:58

Нужно перебрать коллекцию, и вытащить элемент, дата которого равна заданной.
Пишу LINQ запрос:

 manager.VM = DB.FirstOrDefault(x => (x.LaunchTime.CompareTo(chosenvmlauchtime)==0));

Не работает. Пробую последовательно:

 manager.VM = DB.FirstOrDefault(x => (x.LaunchTime==chosenvmlauchtime);
 manager.VM = DB.FirstOrDefault(x =>(x.LaunchTime.Equals(chosenvmlauchtime));
 manager.VM = DB.FirstOrDefault(x =>(Object.Equals(x.LaunchTime, chosenvmlauchtime));

Не работает.
При этом такой монстр:

manager.VM = DB.FirstOrDefault(x => x.LaunchTime.Day==chosenvmlauchtime.Day&&x.LaunchTime.Hour==chosenvmlauchtime.Hour&&x.LaunchTime.Minute==chosenvmlauchtime.Minute&&x.LaunchTime.Second==chosenvmlauchtime.Second);

- работает.

По тому, что нагуглил, должны работать и первые три метода. Но не работают, на выходе null
Что я делаю не так?

Answer 1

Будьте внимательны при сравнении DateTimes, сгенерированных в C#. Структура DateTime в C# имеет более высокую точность, чем тип datetime1 в SQL.

Поэтому, если вы создаете DateTime в C# (скажем, из DateTime.Now), сохраните его в базе данных и верните обратно, это, скорее всего, будет отличаться.

2017.07.07 12:28:23.6115968
2017.07.07 12:28:23.6100000
Answer 2

Когда происходит сравнение двух значений DateTime для того что бы мы получили true два объекта должны быть полностью равны вплоть до DateTime.Ticks, которые представляют число тактов, представляющих дату и время данного экземпляра.

Один такт соответствует 100 наносекундам или одной десятимиллионной секунде. Существует 10 000 тактов в миллисекунде или 10 миллионов тактов в секунде.

Для того что бы понять насколько это быстро, можно провести следующий эксперимент. Создайте последовательно две переменные DateTime и посмотрите значение Ticks. Несмотря на то, что переменные создаются одна за другой количество тактов у них будет разным.

var ticks1 = DateTime.Now.Ticks; // 636350607119477684
var ticks2 = DateTime.Now.Ticks; // 636350607212468695
Answer 3

Итак, вроде как разобрался. Спасибо ответившим, особенно user270576, который натолкнул меня на правильный путь. Проект сделан на EntityFramework code-first. Базу тоже генерил EF. По умолчанию, он ставит тип данных datetime, и в результате, при преобразовании в тип DateTime C# теряется часть данных. Проблема была решена принудительной сменой типа данных в БД на datetime2. После чего заработали и ручной метод с миллисекундами, и стандартные методы. Принудительную смену типа провел через fluentAPI добавлением в метод файла- наследника DBContext. Как-то можно через атрибуты непосредственно в модели, но у меня не получилось.

код метода в файле контекста:

  protected override void  OnModelCreating(DbModelBuilder modelbuilder)
    {
        base.OnModelCreating(modelbuilder);
        modelbuilder.Entity<SiteInfo>().
           Property(p => p.LaunchTime)
           .HasColumnType("datetime2")
           .HasPrecision(0)
           .IsRequired();
    }

ЗЫ: для коллег-начинающих: не забудьте после изменений выполнить в Консоли диспетчера пакетов команды Add-Migration [name] и Upgrade-Database -Verbose для обновления БД.

READ ALSO
C# в классе ArrayList есть два одноименных метода, возвращающих разные значения. WTF?

C# в классе ArrayList есть два одноименных метода, возвращающих разные значения. WTF?

Недавно рыскал по object browser'у, и увидел такую картину

217
Блокировка сетевых портов

Блокировка сетевых портов

Хочу написать програмулину чтобы блокировала все сетевые порты:) этак вирус для начальникаПусть сидит на одном ftp и без танчиков

213
Убрать проверку путей в реестре

Убрать проверку путей в реестре

Подскажите как сделать проверку без использовать Key != null ?

178