Pomelo.entityframeworkcore.mysql: Тип TimeSpan не соответствует типу MySQL TIME

Созданный на 19 мар. 2020  ·  3Комментарии  ·  Источник: PomeloFoundation/Pomelo.EntityFrameworkCore.MySql

Создайте модель с временным интервалом

class MyModel {
   TimeSpan t;
}
---
MyModel m() {t = TimeSpan.MaxValue};
db_context.Add(m);
await db_context.SaveChangesAsync()

Тип TimeSpan создает столбец с типом TIME, который имеет меньшее ограничение, чем TimeSpan. В частности, ВРЕМЯ изменяется только от

Unhandled exception. Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while updating the entries. See the inner exception for details.
 ---> MySql.Data.MySqlClient.MySqlException (0x80004005): Incorrect TIME value: '256204778:48:05.477580'
 ---> MySql.Data.MySqlClient.MySqlException (0x80004005): Incorrect TIME value: '256204778:48:05.477580'
   at MySqlConnector.Core.ServerSession.ReceiveReplyAsyncAwaited(ValueTask`1 task) in C:\projects\mysqlconnector\src\MySqlConnector\Core\ServerSession.cs:line 774
   at MySqlConnector.Core.ResultSet.ReadResultSetHeaderAsync(IOBehavior ioBehavior) in C:\projects\mysqlconnector\src\MySqlConnector\Core\ResultSet.cs:line 49
   at MySql.Data.MySqlClient.MySqlDataReader.ActivateResultSet() in C:\projects\mysqlconnector\src\MySqlConnector\MySql.Data.MySqlClient\MySqlDataReader.cs:line 130
   at MySql.Data.MySqlClient.MySqlDataReader.CreateAsync(CommandListPosition commandListPosition, ICommandPayloadCreator payloadCreator, IDictionary`2 cachedProcedures, IMySqlCommand command, CommandBehavior behavior, IOBehavior ioBehavior, CancellationToken cancellationToken) in C:\projects\mysqlconnector\src\MySqlConnector\MySql.Data.MySqlClient\MySqlDataReader.cs:line 391
   at MySqlConnector.Core.CommandExecutor.ExecuteReaderAsync(IReadOnlyList`1 commands, ICommandPayloadCreator payloadCreator, CommandBehavior behavior, IOBehavior ioBehavior, CancellationToken cancellationToken) in C:\projects\mysqlconnector\src\MySqlConnector\Core\CommandExecutor.cs:line 62
   at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
   --- End of inner exception stack trace ---
   at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(IEnumerable`1 commandBatches, IRelationalConnection connection, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(IList`1 entriesToSave, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(DbContext _, Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
   at Pomelo.EntityFrameworkCore.MySql.Storage.Internal.MySqlExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func`4 operation, Func`4 verifySucceeded, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean acceptAllChangesOnSuccess, CancellationToken cancellationToken)
closed-question type-question

Все 3 Комментарий

Взгляните на Ценностные конверсии , в частности на TimeSpanToStringConverter и TimeSpanToTicksConverter если вам нужен временной интервал больше месяца.

@mguinness Спасибо за подсказку. Правильно ли я интерпретирую преобразователь временного интервала как преобразованный в количество тиков, то есть Long в базе данных?
Также, если вы ничего не можете сделать, я закрою отчет об ошибке.

Тип TimeSpan создает столбец с типом TIME, который имеет меньшее ограничение, чем TimeSpan. В частности, ВРЕМЯ изменяется только от -838: 59: 59.000000 до 838: 59: 59.000000. в то время как TimeSpan может достигать 256204778: 48: 05.477580.

Это ожидаемо. В настоящее время мы обрабатываем TimeSpan как значения меньше 24 часов. Так что даже new TimeSpan(1, 0, 0, 0) работать не будет. Это имитирует поведение SQL Server.

Как отметил @mguinness , здесь можно использовать TimeSpanToTicksConverter . Его можно использовать так:

`` С #
entity.Property (e => e.BestServedBefore)
.HasColumnType ("bigint")
.HasConversion (новый TimeSpanToTicksConverter ());


It is equivalent to the following code:

```c#
entity.Property(e => e.BestServedBefore)
    .HasColumnType("bigint")
    .HasConversion(v => v.Ticks, v => new TimeSpan(v));

Вот полнофункциональный пример:

`` С #
используя Систему;
с помощью System.Diagnostics;
using System.Linq;
using Microsoft.EntityFrameworkCore;
используя Microsoft.EntityFrameworkCore.Storage.ValueConversion;
с использованием Microsoft.Extensions.Logging;
используя Pomelo.EntityFrameworkCore.MySql.Infrastructure;
используя Pomelo.EntityFrameworkCore.MySql.Storage;

пространство имен IssueConsoleTemplate
{
публичный класс IceCream
{
public int IceCreamId {получить; установленный; }
общедоступная строка Имя {получить; установленный; }
общедоступный TimeSpan BestServedBefore {get; установленный; }
}

public class Context : DbContext
{
    public DbSet<IceCream> IceCreams { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder
            .UseMySql(
                "server=127.0.0.1;port=3306;user=root;password=;database=Issue1046",
                b => b
                    .ServerVersion(new ServerVersion("8.0.20-mysql"))
                    .CharSetBehavior(CharSetBehavior.NeverAppend))
            .UseLoggerFactory(
                LoggerFactory.Create(
                    b => b
                        .AddConsole()
                        .AddFilter(level => level >= LogLevel.Information)))
            .EnableSensitiveDataLogging()
            .EnableDetailedErrors();
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<IceCream>(
            entity =>
            {
                entity.Property(e => e.BestServedBefore)
                    .HasColumnType("bigint")
                    .HasConversion(new TimeSpanToTicksConverter());

                entity.HasData(
                    new IceCream
                    {
                        IceCreamId = 1,
                        Name = "Vanilla",
                        BestServedBefore = new TimeSpan(0, 12, 0, 0)
                    },
                    new IceCream
                    {
                        IceCreamId = 2,
                        Name = "Chocolate",
                        BestServedBefore = new TimeSpan(0, 23, 59, 59)
                    },
                    new IceCream
                    {
                        IceCreamId = 3,
                        Name = "Artificial Vanilla",

                        // This will not work out-of-the box.
                        // Usage of a converter is necessary.
                        BestServedBefore = new TimeSpan(42, 11, 0, 0)
                    }
                );
            });
    }
}

internal class Program
{
    private static void Main()
    {
        using var context = new Context();

        context.Database.EnsureDeleted();
        context.Database.EnsureCreated();

        var iceCreams = context.IceCreams
            .OrderBy(i => i.IceCreamId)
            .ToList();

        Debug.Assert(iceCreams.Count == 3);
        Debug.Assert(iceCreams[0].BestServedBefore == new TimeSpan(0, 12, 0, 0));
        Debug.Assert(iceCreams[1].BestServedBefore == new TimeSpan(0, 23, 59, 59));
        Debug.Assert(iceCreams[2].BestServedBefore == new TimeSpan(42, 11, 0, 0));
    }
}

}
`` ''

Была ли эта страница полезной?
0 / 5 - 0 рейтинги

Смежные вопросы

lebartha picture lebartha  ·  3Комментарии

cetubig picture cetubig  ·  3Комментарии

findmoon picture findmoon  ·  3Комментарии

lauxjpn picture lauxjpn  ·  3Комментарии

IonRobu picture IonRobu  ·  3Комментарии