Modelo de Tag
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);
}
using (var context = new TagContext())
{
await context.Tags.InsertAsync(new Tag() { Name = "asdfasdfasdfasdfasdfadsfasdf;jklasdlasdfafsdlj;kafdsljkfsd;ljkf;sdlj;fkjlsd;jklfds" });
await context.SaveAsync();
}
Não importa como eu defino a coluna "nome" com a API fluet, a inserção não cortará a propriedade. Eu tentei:
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();
o modeldef é chamado perfeitamente.
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
Versão MySQL:
Sistema operacional:
Pomelo.EntityFrameworkCore.MySql versão: 3.1.1
Versão Microsoft.AspNetCore.App: .NET Core 3.1
Consulte a documentação de comprimento máximo para propriedades de entidade :
O Entity Framework não faz nenhuma validação do comprimento máximo antes de passar os dados para o provedor. Cabe ao provedor ou armazenamento de dados validar, se apropriado. Por exemplo, ao direcionar o SQL Server, exceder o comprimento máximo resultará em uma exceção, pois o tipo de dados da coluna subjacente não permitirá que dados em excesso sejam armazenados.
@Toemsel Além do que @mguinness disse, também esteja ciente de que varchar(n)
não tem um comprimento fixo. É um tipo de loja de comprimento variável . Seu comprimento fixo equivalente, entretanto, é char(n)
.
Mas mudá-lo de varchar(n)
para char(n)
não fará nenhuma diferença em relação à sua exceção.
Isso ocorre por design.
Se você deseja validar seus dados primeiro, aqui estão alguns artigos sobre isso:
Se você deseja apenas truncar strings antes de enviá-las ao banco de dados, pode ser suficiente usar um conversor de valor , que apenas trunca strings do lado do cliente:
`` `c #
entidade
.Propriedade (t => t.Nome)
.HasMaxLength (32)
.É necessário()
.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, bem, pensei que fluentes / anotações não existiriam apenas para validação / criação / migração. É bom saber e obrigado pela dica.
@lauxjpn Obrigado por me informar sobre o conversor de valor. Isso ajuda muito!
PS: Sim, varchar é dinâmico de 0-32 no meu caso. Foi uma má escolha de palavras.
Obrigado pessoal!
Comentários muito úteis
@Toemsel Além do que @mguinness disse, também esteja ciente de que
varchar(n)
não tem um comprimento fixo. É um tipo de loja de comprimento variável . Seu comprimento fixo equivalente, entretanto, échar(n)
.Mas mudá-lo de
varchar(n)
parachar(n)
não fará nenhuma diferença em relação à sua exceção.Isso ocorre por design.
Se você deseja validar seus dados primeiro, aqui estão alguns artigos sobre isso:
Se você deseja apenas truncar strings antes de enviá-las ao banco de dados, pode ser suficiente usar um conversor de valor , que apenas trunca strings do lado do cliente:
`` `c #
entidade
.Propriedade (t => t.Nome)
.HasMaxLength (32)
.É necessário()
.HasConversion (
v => v.Substring (0, Math.Min (v.Length, 32)),
v => v);