Мне нужно группировать по дате и времени, но в определенном часовом поясе с помощью EF Core и PostgreSQL.C#

Место общения программистов C#
Ответить Пред. темаСлед. тема
Anonymous
 Мне нужно группировать по дате и времени, но в определенном часовом поясе с помощью EF Core и PostgreSQL.

Сообщение Anonymous »

Мне нужно сгруппировать транзакцию по свойству CreatedAt. Но в определенном часовом поясе.
Вот так

Код: Выделить всё

SELECT
SUM("Amount")
FROM
public."Transactions"
GROUP BY
CAST("CreatedAt" AS date) AT TIME ZONE 'America/Chicago'
Но используя EF Core.
Я видел этот подход Мехди и пытался изменить его для PostgreSql.
Вот что у меня есть — построитель выражений:

Код: Выделить всё

public class AtTimeZoneExpression : SqlFunctionExpression
{
private readonly IReadOnlyCollection _params;

public AtTimeZoneExpression(IReadOnlyCollection parameters)
: base("notimportant", true, typeof(DateTimeOffset), RelationalTypeMapping.NullMapping)
{
_params = parameters;
}

protected override Expression Accept(ExpressionVisitor visitor)
{
if (visitor is not QuerySqlGenerator sqlGenerator)
return base.Accept(visitor);

if (_params.First().TypeMapping.DbType == System.Data.DbType.DateTimeOffset)
visitor.Visit(new SqlFragmentExpression("CAST( "));

visitor.Visit(_params.First());

if (_params.First().TypeMapping.DbType == System.Data.DbType.DateTimeOffset)
visitor.Visit(new SqlFragmentExpression(" as date)"));

visitor.Visit(new SqlFragmentExpression(" AT TIME ZONE "));
visitor.Visit(_params.Skip(1).First());

return this;
}

protected override void Print([NotNull] ExpressionPrinter expressionPrinter)
{
expressionPrinter.Append("AT TIME ZONE Expression");
}
}
Функция:

Код: Выделить всё

public static class QueryHelper
{
public static DateTimeOffset ToTimeZone(this DateTimeOffset source, string timeZone)
{
var tz = TimeZoneInfo.FindSystemTimeZoneById(timeZone);
var date = TimeZoneInfo.ConvertTimeFromUtc(source.UtcDateTime, tz);
return new DateTimeOffset(date, tz.GetUtcOffset(date));
}
}
ModelBuilder:

Код: Выделить всё

modelBuilder.HasDbFunction(typeof(QueryHelper).GetMethod(nameof(QueryHelper.ToTimeZone), new[] { typeof(DateTimeOffset), typeof(string) }))
.HasTranslation(args => new AtTimeZoneExpression(args));
И использование:

Код: Выделить всё

var activityPerDay = await transactionQuery
.GroupBy(t => t.CreatedAt.ToTimeZone(timeZoneId).Date)
.Select(dayGroup => new ItemMetrics
{
DateTime = dayGroup.Key,
Volume = dayGroup.Sum(t => t.Amount ?? 0)
})
.ToListAsync(cancellationToken);
Я использую EF Core версии 8.0.10.
Вот что я получаю

Код: Выделить всё

t => t.CreatedAt.ToTimeZone(timeZoneId).Date
(

Код: Выделить всё

CreatedAt
— это столбец DateTimeOffset, не допускающий значения NULL)

System.ArgumentException: аргумент метки времени для AtTimeZone имел неизвестный тип хранилища NULL (параметр ' timestamp')
в Npgsql.EntityFrameworkCore.PostgreSQL.Query.NpgsqlSqlExpressionFactory.AtTimeZone(временная метка SqlExpression, SqlExpression timeZone, Type type, RelationalTypeMapping typeMapping)

в Npgsql. EntityFrameworkCore.PostgreSQL.Query.NpgsqlSqlExpressionFactory.AtUtc(временная метка SqlExpression, RelationalTypeMapping typeMapping)

at Npgsql.EntityFrameworkCore.PostgreSQL.Query.ExpressionTranslators.Internal.NpgsqlDateTimeMemberTranslator.TranslateDateTimeOffset(SqlExpression экземпляр, для участника)

at Npgsql.EntityFrameworkCore.PostgreSQL.Query.ExpressionTranslators.Internal.NpgsqlDateTimeMemberTranslator.Translate (экземпляр SqlExpression, член MemberInfo, тип returnType, IDiagnosticsLogger

Код: Выделить всё

1 logger)   at Microsoft.EntityFrameworkCore.Query.RelationalMemberTranslatorProvider.c__DisplayClass6_0.b__0(IMemberTranslator t)   at System.Linq.Enumerable.SelectEnumerableIterator
2.MoveNext()

Я также пробовал добавлять NodaTime в контекст и использовать переводимые функции.

Код: Выделить всё

builder.Services.AddDbContext(options => options.UseNpgsql(
"",
o => o.UseNodaTime()));
Но это тоже не сработало.

Подробнее здесь: https://stackoverflow.com/questions/791 ... postgresql
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «C#»