Из моего приложения C# я вызываю хранимую процедуру с TVP
. Пара столбцов datetime
. Вызов SP может выглядеть следующим образом:
declare @p1 dbo.MyTvp
insert into @p1 values('2020-03-19 00:00:01','2020-03-30 23:59:59')
exec MySp @criteria=@p1
Код выше автоматически генерируется в C#. В SP часть обработки дат:
declare @datefrom datetime;
---
SET @sql = CONCAT(@sql, ' AND date_from >= ''', @datefrom, '''');
SQL Язык интерфейса сервера - немецкий.
Приведенное выше сообщение вызывает ошибку из-за преобразования из varchar в datetime. Однако, если значения даты и времени, которые я передаю, отформатированы следующим образом:
declare @p1 dbo.MyTvp
insert into @p1 values('19.03.2020 00:00:01','30.03.2020 23:59:59')
exec MySp @criteria=@p1
SP работает нормально.
Класс, используемый в качестве источника:
public class MyCriteria
{
public DateTime DateFrom { get; set; }
}
И тип таблицы:
CREATE TYPE [dbo].[MyTvp] AS TABLE(
[DateFrom] [datetime] NULL
)
Я преобразую экземпляр MyCriteria
в DataTable
, используя метод расширения, а затем использую Dapper для выполнения SP:
var criteria = new List<MyCriteria>() { myCriteria }.ToDataTable();
return await conn.QueryAsync<SomeResult>(new CommandDefinition("MySp", new { criteria }, commandType: CommandType.StoredProcedure, cancellationToken: ct));
Я не понимаю, на каком этапе происходит преобразование из datetime
в varchar
или DateTime
в string
.
Так как именно мне нужно преобразовать даты в заставить SP работать? Должен ли я выполнять преобразование на уровне БД или в моем приложении C#?
РЕДАКТИРОВАТЬ
Это метод расширения, используемый для преобразования класса в таблицу данных, поэтому что он может быть передан в качестве TVP на SP:
public static DataTable ToDataTable<T>(this IEnumerable<T> items)
{
var dataTable = new DataTable(typeof(T).Name);
//Get all the properties not marked with Ignore attribute
var properties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance)
.Where(x => x.GetCustomAttributes(typeof(XmlIgnoreAttribute), false).Length == 0).ToList();
//Set column names as property names
foreach (var property in properties)
{
if (!property.PropertyType.IsEnum && !property.PropertyType.IsNullableEnum())
{
var type = property.PropertyType;
//Check if type is Nullable like int?
if (Nullable.GetUnderlyingType(type) != null)
type = Nullable.GetUnderlyingType(type);
dataTable.Columns.Add(property.Name, type);
}
else dataTable.Columns.Add(property.Name, typeof(int));
}
//Insert property values to datatable rows
foreach (T item in items)
{
var values = new object[properties.Count];
for (int i = 0; i < properties.Count; i++)
{
values[i] = properties[i].GetValue(item, null);
}
dataTable.Rows.Add(values);
}
return dataTable;
}
EDIT 2
Проблема в SQL, который генерируется C # / Dapper, который используется для заполнения TVP, переданного SP. Простой тест можно увидеть, выполнив следующее:
DECLARE @test TABLE (
[DateCol] datetime NOT NULL
);
INSERT INTO @test VALUES ('2020-02-19 00:00:01'); --doesnt work
INSERT INTO @test VALUES (CONVERT(datetime, '2020-02-19 00:00:01', 120)); --works
Функция CONVERT
возвращает дату в том же формате, что и первый оператор INSERT
. Однако первое утверждение не работает.