25 августа 2017 г.

MSSQL DATETIME2, DATETIME truncate минуты, секунд.

В какой то момент может понадобится  возможность в SQL запросе по полю типа DATETIME или DATETIME2 производить сравнение дат с какой то конкретной датой, отбросив при этом минуты, секунды, миллисекунды. Для дат, которые лежат в настоящие годы, это можно сделать без каких либо проблем через DATEADD и DATEDIFF. Пример использования с обрезанием до минут:

SELECT DATEADD(MINUTE, DATEDIFF(MINUTE, 0, '2017-08-25 00:00'), 0)

В случае, если требуется обрезание до секунд, миллисекунд или любой другой составляющей даты достаточно поменять первый параметр метода DATEADD и DATEDIFF на нужный тип. Список типов одинаков и описан на msdn каждого метода.

Все было бы хорошо, но есть ложка дёгтя в бочке с медом. DATEDIFF возвращает количество прошедших минут, секунд, миллисекунд с 1900-01-01 00:00:00 при этом возвращаемое значение INT. Это значит:
  • Даты до 1900 года будут иметь отрицательное значение
  • Мы имеем ограничение на возвращаемое значение, равное диапазону значений INT, а это ровняется от -2,147,483,648 до +2,147,483,647.
  • Чем меньшую единицу измерения времени мы хотим обрезать, тем ближе к 1900 году должна быть дата в таблице.
При этом, максимальный год для DATETIME и DATETIME2 это 9999. И если в таблице будет присутствовать значение, которая будет приводить к переполнению INT при вычисление DATEDIFF - вы будете получать ошибку на ваш SQL запрос:
The datediff function resulted in an overflow. The number of dateparts separating two date/time instances is too large. Try to use datediff with a less precise datepart.

15 августа 2017 г.

Решение проблемы при установке ccollab клиента.

Столкнулся с проблемой при обновлении клиента Code Review - Collaborator от SmartBear с 6.x на 11.x. Для установки я удалил старую версию и решил поставить новую, но в ответ получил ошибку:


Формат текста ошибки следующий:
The installation/removal of a previous program was not completed. You will need to restart your computer to complete that installation.\n\nAfter restarting your computer, run Setup again to complete the installation of {0}.
Для её решения я используя Process Explorer открыл текущую директорию у для установщика, она была во временной папке по пути C:\Users\SAP\AppData\Local\Temp\[Random], в папке содержался файла MessagesDefault в котором было само сообщение с ключем PreviousInstallNotCompleted. Декомпилировав было выяснено, что в файле i4jruntime.jar, лежащем в каталоге, содержится часть логики установщика. После непродолжительного анализа была найдена проверка и выдача ошибки, а логика такая:
  • Читаем из HKEY_CURRENT_USER и HKEY_LOCAL_MACHINE значение RebootCheckFile по адресу SOFTWARE\ej-technologies\install4j\.
  • Если файл по пути RebootCheckFile существует то падаем с ошибкой.
Почему у меня не удалился файл я не знаю, но действительно, по пути C:\Users\SAP\AppData\Local\Temp\ существовал пустой файл, который стопарил все.



Удаляем RebootCheckFile и все! Установка должна пройти успешно.

14 августа 2017 г.

Учим Ecm7.Migrator работать с MSSQL типом DATETIME2

Сегодня хотелось бы рассказать зачем мы начали использовать ECM7.Migrator и как его научить понимать DbType.DateTime2 на версии ECM7 2.8.0.0.

Зачем использовать ECM7?


Всю информацию можно узнать на сайте проекта ECM7.Migrator ссылка на NuGet. Тут я опишу почему мы его стали использовать на работе. В решениях используем EntityFramework с Code First подход при работе с базой данных. Для этого EntityFramework умеет создавать, на основе объектной модели, сущности в базе данных. Данные об этих сущностях хранятся в миграциях, а их применением и версионностью занимается DbMigrator. Все было бы хорошо, но есть одно ограничение - все миграции должны находиться в проекте с DbContext. И в ситуации, если решение состоит из плагинов, каждому из которых требуется своя структура в базе, это ограничение требует, что бы все миграции до подключения плагина уже были применены к базе. Но в этом случае теряется смысл в выделении модулей и подключении только нужных.

Для решения мы использовали ECM7.Migrator, на который пришлось переписать создание базы данных решения, а модульные миграции без проблем перенесли в другие сборки.

Работа с DateTime2.


Решения из коробки у версии ECM7 2.8.0.0, для работы с типом DateTime2, найдено не было, но это лечится простым добавлением типа в карту типов SqlServerTransformationProvider.


using System.Data;
using System.Data.SqlClient;
 
namespace ECM7.Migrator.Providers.SqlServer
{
    /// <summary>
    /// Extended <see cref="SqlServerTransformationProvider"/> MSSQL provider.
    /// </summary>
    internal class ExtendedSqlServerTransformationProvider : SqlServerTransformationProvider
    {
        /// <summary>
        /// <see cref="ExtendedSqlServerTransformationProvider"/> constructor.
        /// </summary>
        public ExtendedSqlServerTransformationProvider(SqlConnection connection, int commandTimeout)
            : base(connection, commandTimeout)
        {
            typeMap.Put(DbType.DateTime2, "DATETIME2");
        }
    }
}