У меня есть две сущности в базе данных, которые содержат DateTime в двух разных форматах;SuperLogs.EndTime
является нормальным DateTime
, тогда как SuperLogs.Logs
содержит DateTime как отдельные числовые компоненты Year
(int
), Month
(int
), Day
(int
) и Time
(double
).Что я хочу сделать в своем запросе, так это получить единственную SuperLogs
сущность, последняя версия которой имеет DateTime больше, чем EndTime
из superLogX
.
У меня есть функция C # (GetLogDateTime
) дляпреобразовать DateTime для Logs
в фактический DateTime
, но при передаче в следующем запросе «System.InvalidOperationException: внутренняя ошибка .25 данных поставщика .NET Framework».
var superLogNewerThanSuperLogX = await MyDbContext.SuperLogs.SingleOrDefaultAsync
(
superLog => superLog.Logs.Max<Log, DateTime>(GetLogDateTime) > superLogX.EndTime
);
GetLogDateTime
реализован следующим образом:
private static DateTime GetLogDateTime(Log log)
{
var time = log.Time;
var hasTime = log.Time.HasValue;
var hours = hasTime ? Math.Floor(time.Value / 10000) : 0;
var minutes = hasTime ? Math.Floor(time.Value / 100) - hours * 100 : 0;
return new DateTime
(
log.Year,
log.Month,
log.Day,
(int)hours,
(int)minutes,
hasTime ? (int)(time.Value - (hours * 10000 + minutes * 100)) : 0,
hasTime ? (int)((time.Value - Math.Truncate(time.Value)) * 1000) : 0
);
}
Я думаю, что часть проблемы заключается в том, что GetLogDateTime конвертирует только в Func<Log, DateTime>
, но необходимо преобразоватьв Expression<Func<Log, DateTime>>
как-то.Я не уверен, как это сделать, и если это невозможно, у меня также есть скалярная функция, реализованная в базе данных, которая выполняет ту же задачу, что и этот метод.
CREATE FUNCTION dbo.CreateDateTime
(
@year SMALLINT,
@month SMALLINT,
@day SMALLINT,
@time FLOAT
)
RETURNS DATETIME AS
BEGIN
DECLARE @paddedYear VARCHAR(4) = REPLACE(STR(@year, 4), SPACE(1), '0')
DECLARE @paddedMonth VARCHAR(2) = REPLACE(STR(@month, 2), SPACE(1), '0')
DECLARE @paddedDay VARCHAR(2) = REPLACE(STR(@day, 2), SPACE(1), '0')
DECLARE @hours FLOAT = ROUND(@time / 10000, 0, 1)
DECLARE @hoursAndMinutes FLOAT = ROUND(@time / 100, 0, 1)
DECLARE @hoursMinutesAndSeconds FLOAT = ROUND(@time, 0, 1)
--DATETIME only supports 3 decimal places on seconds so VARCHAR 5 is the max needed for the string 0.xxx
DECLARE @milliseconds VARCHAR(5) = CAST(@time - ROUND(@time, 0, 1) AS VARCHAR(5))
RETURN IIF
(
@year IS NULL
OR @month IS NULL
OR @day IS NULL,
NULL,
CAST
(
IIF
(
@time IS NULL,
@paddedYear
+ @paddedMonth
+ @paddedDay,
@paddedYear
+ @paddedMonth
+ @paddedDay
+ ' '
--In ROUND, the final argument of 1 forces ROUND to always round down (desired here).
+ REPLACE(STR(@hours, 2), SPACE(1), '0')
+ ':'
+ REPLACE(STR(@hoursAndMinutes - @hours * 100, 2), SPACE(1), '0')
+ ':'
+ REPLACE(STR(@hoursMinutesAndSeconds - @hoursAndMinutes * 100, 2), SPACE(1), '0')
+ IIF
(
@time <> @hoursMinutesAndSeconds,
'.'
+ SUBSTRING(@milliseconds, 3, LEN(@milliseconds) - 2),
''
)
)
AS DATETIME
)
)
END
Однако это не особенно помогаетпоскольку я не могу заставить Entity Framework позволить мне это называть!На данный момент единственная жизнеспособная опция, которую я вижу, - это попытаться переместить весь мой запрос (намного больше, чем показано здесь) в базу данных в виде хранимой процедуры.Есть ли другой способ или это то, что я буду вынужден сделать?