Pomelo.entityframeworkcore.mysql: API fluida con varchar de longitud fija

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

pasos para reproducir

image

Modelo de etiqueta

public class Tag : BaseModel
{
    public string Name { get; set; }

    public DateTime Creation { get; set; }

    public int UsageCount { get; set; }

    public int Likes { get; set; }

    public int Dislikes { get; set; }

    public bool IsActive { get; set; }

    public override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Tag>(entity =>
        {
            entity.HasKey(t => t.Id);
            entity.Property(t => t.Id).ValueGeneratedOnAdd();

            entity.Property(t => t.Name).IsFixedLength(true).HasColumnType("VARCHAR(32)").HasMaxLength(32).IsRequired();
            entity.Property(t => t.Creation).HasDefaultValue(DateTime.Now).IsRequired();
            entity.Property(t => t.UsageCount).HasDefaultValue(0).IsRequired();
            entity.Property(t => t.Likes).HasDefaultValue(0).IsRequired();
            entity.Property(t => t.Dislikes).HasDefaultValue(0).IsRequired();
            entity.Property(t => t.IsActive).HasDefaultValue(true).IsRequired();
        });
    }
}

DbContext

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        foreach (var currentModel in Assembly.GetExecutingAssembly().GetTypes().Where(t => t.IsSubclassOf(typeof(BaseModel)) && !t.IsAbstract))
            ((BaseModel)Activator.CreateInstance(currentModel)).OnModelCreating(modelBuilder);

        base.OnModelCreating(modelBuilder);
    }

La cuestión

        using (var context = new TagContext())
        {
            await context.Tags.InsertAsync(new Tag() { Name = "asdfasdfasdfasdfasdfadsfasdf;jklasdlasdfafsdlj;kafdsljkfsd;ljkf;sdlj;fkjlsd;jklfds" });
            await context.SaveAsync();
        }

image

No importa cómo defina la columna "nombre" con la API fluet, la inserción no recortará la propiedad. Lo intenté:

            entity.Property(t => t.Name).IsFixedLength(true).HasColumnType("VARCHAR(32)").HasMaxLength(32).IsRequired();
            entity.Property(t => t.Name).IsFixedLength(true).HasMaxLength(32).IsRequired();
            entity.Property(t => t.Name).HasMaxLength(32).IsRequired();
            entity.Property(t => t.Name).IsFixedLength(true).HasColumnType("VARCHAR(32)").IsRequired();
            entity.Property(t => t.Name).HasColumnType("VARCHAR(32)").IsRequired();

el modeldef se llama sin problemas.

Exception message: Exception thrown: 'Microsoft.EntityFrameworkCore.DbUpdateException' in System.Private.CoreLib.dll
Stack trace:    at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.<ExecuteAsync>d__29.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.<ExecuteAsync>d__8.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.<ExecuteAsync>d__8.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.<SaveChangesAsync>d__93.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.<SaveChangesAsync>d__97.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at Pomelo.EntityFrameworkCore.MySql.Storage.Internal.MySqlExecutionStrategy.<ExecuteAsync>d__7`2.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at Microsoft.EntityFrameworkCore.DbContext.<SaveChangesAsync>d__54.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at DBCT.Persistence.Repository.EntityFramework.EntityFrameworkUnitOfWork.<SaveAsync>d__5.MoveNext() in C:\Users\thoma\source\repos\DBCT\DBCT.Persistence\Repository\EntityFramework\EntityFrameworkUnitOfWork.cs:line 22

Más detalles técnicos

Versión de MySQL:
image

Sistema operativo:
image

Pomelo.EntityFrameworkCore.MySql versión: 3.1.1
Versión de Microsoft.AspNetCore.App: .NET Core 3.1

closed-question type-question

Comentario más útil

@Toemsel Además de lo que dijo @mguinness , también tenga en cuenta que varchar(n) no tiene una longitud fija. Es un tipo de tienda de longitud variable . Sin embargo, su longitud fija es equivalente a char(n) .

Pero cambiarlo de varchar(n) a char(n) no hará ninguna diferencia con respecto a su excepción.
Esto es por diseño.

Si desea validar sus datos primero, aquí hay algunos artículos al respecto:

Si solo desea truncar cadenas antes de enviarlas a la base de datos, podría ser suficiente que use un Convertidor de valores , que simplemente trunca las cadenas del lado del cliente:

`` c #
entidad
.Propiedad (t => t.Name)
.Tiene Longitud Máxima (32)
.Se requiere()
.HasConversion (
v => v.Substring (0, Math.Min (v.Length, 32)),
v => v);


If you want to automate this, based on whether `MaxLength` has been defined or not, you can do that as well. Take a look at the following console app:

```c#
using System;
using System.Diagnostics;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Microsoft.Extensions.Logging;
using Pomelo.EntityFrameworkCore.MySql.Storage;

namespace IssueConsoleTemplate
{
    public class IceCream
    {
        public int IceCreamId { get; set; }
        public string Name { get; set; }
    }

    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=Issue1058",
                    b => b.ServerVersion(new ServerVersion("8.0.20-mysql")))
                .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.Name)
                        .HasMaxLength(5)
                        .IsRequired();
                });

            foreach (var entityType in modelBuilder.Model.GetEntityTypes())
            {
                foreach (var property in entityType.GetProperties())
                {
                    var maxLength = property.GetMaxLength().GetValueOrDefault();
                    if (maxLength > 0)
                    {
                        property.SetValueConverter(new ValueConverter<string,string>(
                            v => v.Substring(0, Math.Min(v.Length, maxLength)),
                            v => v));
                    }
                }
            }
        }
    }

    internal class Program
    {
        private static void Main()
        {
            using (var context = new Context())
            {
                context.Database.EnsureDeleted();
                context.Database.EnsureCreated();
            }

            using (var context = new Context())
            {
                context.IceCreams.Add(new IceCream {Name = "Vanilla"});
                context.SaveChanges();
            }

            using (var context = new Context())
            {
                var iceCreams = context.IceCreams.ToList();

                Debug.Assert(iceCreams.Count == 1);
                Debug.Assert(iceCreams[0].Name == "Vanil");
            }
        }
    }
}

Todos 3 comentarios

Consulte la documentación de longitud máxima para las propiedades de la entidad :

Entity Framework no realiza ninguna validación de la longitud máxima antes de pasar los datos al proveedor. Depende del proveedor o del almacén de datos validar si es apropiado. Por ejemplo, al apuntar a SQL Server, exceder la longitud máxima resultará en una excepción ya que el tipo de datos de la columna subyacente no permitirá que se almacenen datos en exceso.

@Toemsel Además de lo que dijo @mguinness , también tenga en cuenta que varchar(n) no tiene una longitud fija. Es un tipo de tienda de longitud variable . Sin embargo, su longitud fija es equivalente a char(n) .

Pero cambiarlo de varchar(n) a char(n) no hará ninguna diferencia con respecto a su excepción.
Esto es por diseño.

Si desea validar sus datos primero, aquí hay algunos artículos al respecto:

Si solo desea truncar cadenas antes de enviarlas a la base de datos, podría ser suficiente que use un Convertidor de valores , que simplemente trunca las cadenas del lado del cliente:

`` c #
entidad
.Propiedad (t => t.Name)
.Tiene Longitud Máxima (32)
.Se requiere()
.HasConversion (
v => v.Substring (0, Math.Min (v.Length, 32)),
v => v);


If you want to automate this, based on whether `MaxLength` has been defined or not, you can do that as well. Take a look at the following console app:

```c#
using System;
using System.Diagnostics;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Microsoft.Extensions.Logging;
using Pomelo.EntityFrameworkCore.MySql.Storage;

namespace IssueConsoleTemplate
{
    public class IceCream
    {
        public int IceCreamId { get; set; }
        public string Name { get; set; }
    }

    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=Issue1058",
                    b => b.ServerVersion(new ServerVersion("8.0.20-mysql")))
                .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.Name)
                        .HasMaxLength(5)
                        .IsRequired();
                });

            foreach (var entityType in modelBuilder.Model.GetEntityTypes())
            {
                foreach (var property in entityType.GetProperties())
                {
                    var maxLength = property.GetMaxLength().GetValueOrDefault();
                    if (maxLength > 0)
                    {
                        property.SetValueConverter(new ValueConverter<string,string>(
                            v => v.Substring(0, Math.Min(v.Length, maxLength)),
                            v => v));
                    }
                }
            }
        }
    }

    internal class Program
    {
        private static void Main()
        {
            using (var context = new Context())
            {
                context.Database.EnsureDeleted();
                context.Database.EnsureCreated();
            }

            using (var context = new Context())
            {
                context.IceCreams.Add(new IceCream {Name = "Vanilla"});
                context.SaveChanges();
            }

            using (var context = new Context())
            {
                var iceCreams = context.IceCreams.ToList();

                Debug.Assert(iceCreams.Count == 1);
                Debug.Assert(iceCreams[0].Name == "Vanil");
            }
        }
    }
}

@mguinness oh, bueno, pensé que la fluidez / anotaciones no solo existiría para validación / creación / migración solo. Es bueno saberlo y gracias por la pista.

@lauxjpn Gracias por

PD: Sí, varchar es dinámico de 0 a 32 en mi caso. Fue una mala elección de palabras.

¡Gracias chicos!

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