Pomelo.entityframeworkcore.mysql: El tipo TimeSpan no se asigna correctamente al tipo TIME MySQL

Creado en 19 mar. 2020  ·  3Comentarios  ·  Fuente: PomeloFoundation/Pomelo.EntityFrameworkCore.MySql

Crea un modelo con un intervalo de tiempo

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

El tipo TimeSpan crea una columna de tipo TIME que tiene una restricción menor que TimeSpan. Específicamente, TIME solo va de '-838: 59: 59.000000' a '838: 59: 59.000000' . mientras que TimeSpan puede llegar a 256204778: 48: 05.477580.

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

Todos 3 comentarios

Eche un vistazo a las conversiones de valor , específicamente TimeSpanToStringConverter y TimeSpanToTicksConverter si necesita un período de tiempo superior a un mes.

@mguinness Gracias por la sugerencia. ¿Estoy en lo correcto al interpretar que el convertidor de intervalo de tiempo se traduce en un número de ticks, que es un Long en la base de datos?
Además, si no hay nada que pueda hacer, cerraré el informe de error.

El tipo TimeSpan crea una columna de tipo TIME que tiene una restricción menor que TimeSpan. Específicamente, TIME solo va de '-838: 59: 59.000000' a '838: 59: 59.000000'. mientras que TimeSpan puede llegar a 256204778: 48: 05.477580.

Se esperaba esto. Actualmente manejamos TimeSpan como valores menores a 24 horas. Entonces, incluso new TimeSpan(1, 0, 0, 0) no funcionará. Esto imita el comportamiento de SQL Server.

Como señaló @mguinness , usar TimeSpanToTicksConverter es el camino a seguir aquí. Se puede usar así:

`` c #
entidad.Propiedad (e => e.BestServedBefore)
.HasColumnType ("bigint")
.HasConversion (nuevo TimeSpanToTicksConverter ());


It is equivalent to the following code:

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

Aquí hay un ejemplo completamente funcional:

`` c #
usando el sistema;
utilizando System.Diagnostics;
utilizando System.Linq;
utilizando Microsoft.EntityFrameworkCore;
utilizando Microsoft.EntityFrameworkCore.Storage.ValueConversion;
utilizando Microsoft.Extensions.Logging;
utilizando Pomelo.EntityFrameworkCore.MySql.Infrastructure;
usando Pomelo.EntityFrameworkCore.MySql.Storage;

espacio de nombres IssueConsoleTemplate
{
IceCream clase pública
{
public int IceCreamId {obtener; colocar; }
Nombre de la cadena pública {get; colocar; }
public TimeSpan BestServedBefore {get; colocar; }
}

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));
    }
}

}
''

¿Fue útil esta página
0 / 5 - 0 calificaciones