Sto lavorando a un'applicazione core 2.1 core con core di framework di entità e SQL Server 2017 Express Edition. Ho creato la migrazione e fatto l'aggiornamento e tutto è andato liscio, tuttavia, quando ho interrogato il database ho notato che la dimensione dei campi non è stata applicata in base alle migrazioni.
Come posso risolvere questo problema nella mia migrazione?
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "Fornecedor",
columns: table => new
{
Id = table.Column<Guid>(nullable: false),
IdSistemaAntigo = table.Column<string>(type: "varchar", maxLength: 32, nullable: false),
Status = table.Column<int>(nullable: false),
DataCadastro = table.Column<DateTime>(nullable: false),
UltimaMovimentacao = table.Column<DateTime>(nullable: false),
TipoPessoa = table.Column<int>(nullable: false),
Nome = table.Column<string>(type: "varchar", maxLength: 100, nullable: false),
Apelido = table.Column<string>(type: "varchar", maxLength: 100, nullable: true),
Sexo = table.Column<int>(nullable: true),
Cnpj = table.Column<string>(type: "varchar", maxLength: 14, nullable: false),
InscricaoEstadual = table.Column<string>(type: "varchar", maxLength: 15, nullable: false),
EstadoEmissorInscricaoEstadual = table.Column<string>(type: "varchar", maxLength: 2, nullable: false),
InscricaoMunicipal = table.Column<string>(type: "varchar", maxLength: 20, nullable: false),
Cpf = table.Column<string>(type: "varchar", maxLength: 11, nullable: false),
Rg = table.Column<string>(type: "varchar", maxLength: 15, nullable: false),
EstadoEmissorRg = table.Column<string>(type: "varchar", maxLength: 2, nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_Fornecedor", x => x.Id);
});
migrationBuilder.CreateTable(
name: "FornecedorEmail",
columns: table => new
{
Id = table.Column<Guid>(nullable: false),
IdSistemaAntigo = table.Column<string>(type: "varchar", maxLength: 32, nullable: false),
Status = table.Column<int>(nullable: false),
DataCadastro = table.Column<DateTime>(nullable: false),
UltimaMovimentacao = table.Column<DateTime>(nullable: false),
FornecedorId = table.Column<Guid>(nullable: false),
EnderecoEmail = table.Column<string>(type: "varchar", maxLength: 254, nullable: false),
NomeExibicao = table.Column<string>(type: "varchar", maxLength: 40, nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_FornecedorEmail", x => x.Id);
table.ForeignKey(
name: "FK_FornecedorEmail_Fornecedor_FornecedorId",
column: x => x.FornecedorId,
principalTable: "Fornecedor",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "FornecedorEndereco",
columns: table => new
{
Id = table.Column<Guid>(nullable: false),
IdSistemaAntigo = table.Column<string>(type: "varchar", maxLength: 32, nullable: false),
Status = table.Column<int>(nullable: false),
DataCadastro = table.Column<DateTime>(nullable: false),
UltimaMovimentacao = table.Column<DateTime>(nullable: false),
TipoLogradouro = table.Column<string>(type: "varchar", maxLength: 72, nullable: false),
Logradouro = table.Column<string>(type: "varchar", maxLength: 72, nullable: false),
Numero = table.Column<string>(type: "varchar", maxLength: 6, nullable: false),
Bairro = table.Column<string>(type: "varchar", maxLength: 72, nullable: false),
Complemento = table.Column<string>(type: "varchar", maxLength: 72, nullable: false),
Cidade = table.Column<string>(type: "varchar", maxLength: 72, nullable: false),
Estado = table.Column<string>(type: "varchar", maxLength: 2, nullable: false),
Pais = table.Column<string>(type: "varchar", maxLength: 2, nullable: false),
Cep = table.Column<string>(type: "varchar", maxLength: 8, nullable: false),
CodigoIbge = table.Column<string>(type: "varchar", maxLength: 7, nullable: false),
Identificador = table.Column<string>(nullable: false),
FornecedorId = table.Column<Guid>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_FornecedorEndereco", x => x.Id);
table.ForeignKey(
name: "FK_FornecedorEndereco_Fornecedor_FornecedorId",
column: x => x.FornecedorId,
principalTable: "Fornecedor",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "FornecedorTelefone",
columns: table => new
{
Id = table.Column<Guid>(nullable: false),
IdSistemaAntigo = table.Column<string>(type: "varchar", maxLength: 32, nullable: false),
Status = table.Column<int>(nullable: false),
DataCadastro = table.Column<DateTime>(nullable: false),
UltimaMovimentacao = table.Column<DateTime>(nullable: false),
Ddi = table.Column<string>(type: "varchar", maxLength: 4, nullable: false),
Ddd = table.Column<string>(type: "varchar", maxLength: 4, nullable: false),
Telefone = table.Column<string>(type: "varchar", maxLength: 9, nullable: false),
Ramal = table.Column<string>(type: "varchar", maxLength: 4, nullable: false),
TipoTelefone = table.Column<string>(type: "varchar", maxLength: 1, nullable: false),
Identificador = table.Column<string>(nullable: false),
FornecedorId = table.Column<Guid>(nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_FornecedorTelefone", x => x.Id);
table.ForeignKey(
name: "FK_FornecedorTelefone_Fornecedor_FornecedorId",
column: x => x.FornecedorId,
principalTable: "Fornecedor",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_FornecedorEmail_FornecedorId",
table: "FornecedorEmail",
column: "FornecedorId");
migrationBuilder.CreateIndex(
name: "IX_FornecedorEndereco_FornecedorId",
table: "FornecedorEndereco",
column: "FornecedorId");
migrationBuilder.CreateIndex(
name: "IX_FornecedorTelefone_FornecedorId",
table: "FornecedorTelefone",
column: "FornecedorId");
}
Dimensione del campo di migrazione errata
Questa è la mia classe di migrazione
public override void ConfigurarEntidade(EntityTypeBuilder<Fornecedor> builder)
{
builder.ToTable("Fornecedor");
#region Configurações da Entidade
builder.Property(fornecedor => fornecedor.TipoPessoa)
.HasColumnType("varchar")
.HasMaxLength(1)
.IsRequired();
builder.Property(fornecedor => fornecedor.Nome)
.IsRequired()
.HasColumnType("varchar")
.HasMaxLength(Fornecedor.TamanhoNome);
builder.Property(fornecedor => fornecedor.Apelido)
.HasColumnType("varchar")
.HasMaxLength(Fornecedor.TamanhoNome);
builder.Property(fornecedor => fornecedor.Sexo)
.IsRequired(false);
builder.OwnsOne(fornecedor => fornecedor.Cnpj, cnpj =>
{
cnpj.Property(fornecedor => fornecedor.NumeroCnpj)
.HasColumnType("varchar")
.HasColumnName("Cnpj")
.HasMaxLength(Cnpj.TamanhoCnpj)
.IsRequired();
});
builder.OwnsOne(fornecedor => fornecedor.InscricaoEstadual, ie =>
{
ie.Property(fornecedor => fornecedor.NumeroInscricao)
.HasColumnType("varchar")
.HasColumnName("InscricaoEstadual")
.HasMaxLength(InscricaoEstadual.TamanhoInscricaoEstadual)
.IsRequired();
ie.Property(fornecedor => fornecedor.EstadoEmissor)
.HasColumnType("varchar")
.HasColumnName("EstadoEmissorInscricaoEstadual")
.HasMaxLength(InscricaoEstadual.TamanhoEstadoEmissor)
.IsRequired();
});
builder.Property(fornecedor => fornecedor.InscricaoMunicipal)
.HasColumnType("varchar")
.HasColumnName("InscricaoMunicipal")
.HasMaxLength(Fornecedor.TamanhoInscricaoMunicipal)
.IsRequired();
builder.OwnsOne(fornecedor => fornecedor.Cpf, cpf =>
{
cpf.Property(fornecedor => fornecedor.NumeroCpf)
.HasColumnType("varchar")
.HasColumnName("Cpf")
.HasMaxLength(Cpf.TamanhoMaximoCpf)
.IsRequired();
});
builder.OwnsOne(fornecedor => fornecedor.Rg, rg =>
{
rg.Property(fornecedor => fornecedor.NumeroRg)
.HasColumnType("varchar")
.HasColumnName("Rg")
.HasMaxLength(Rg.TamanhoRg)
.IsRequired();
rg.Property(fornecedor => fornecedor.EstadoEmissor)
.HasColumnType("varchar")
.HasColumnName("EstadoEmissorRg")
.HasMaxLength(Rg.TamanhoEstadoEmissor)
.IsRequired();
});
builder.Ignore(fornecedor => fornecedor.DataNascimento);
builder.Ignore(fornecedor => fornecedor.Imagem);
#endregion
#region Relacionamentos
builder
.HasMany(fornecedor => fornecedor.Emails)
.WithOne(email => email.Fornecedor)
.HasForeignKey(email => email.FornecedorId);
builder
.HasMany(fornecedor => fornecedor.Enderecos)
.WithOne(endereco => endereco.Fornecedor)
.HasForeignKey(endereco => endereco.FornecedorId);
builder
.HasMany(fornecedor => fornecedor.Telefones)
.WithOne(telefone => telefone.Fornecedor)
.HasForeignKey(telefone => telefone.FornecedorId);
#endregion
}
E questa è la mia Entità
public class Fornecedor : Entity
{
public static readonly int TamanhoNome = 100;
public static readonly int TamanhoApelido = 20;
public static readonly int TamanhoInscricaoMunicipal = 20;
public static readonly int TamanhoRg = 20;
private string _nome;
private string _nomeFantasia;
public TipoPessoa TipoPessoa { get; private set; }
public string Nome
{
get { return _nome; }
private set { _nome = (value == null ? "" : value.RemoverEspacosDuplos().ToCapitalize().Trim()); }
}
public string Apelido
{
get { return _nomeFantasia; }
private set { _nomeFantasia = (value == null ? "" : value.RemoverEspacosDuplos().ToCapitalize().Trim()); }
}
public Sexo? Sexo { get; private set; }
public Cnpj Cnpj { get; private set; }
public InscricaoEstadual InscricaoEstadual { get; private set; }
public string InscricaoMunicipal { get; private set; }
public Cpf Cpf { get; private set; }
public Rg Rg { get; private set; }
public DateTime? DataNascimento { get; private set; }
public string Imagem { get; private set; }
public Fornecedor() { }
}
Il problema è il type: "varchar"
argomento type: "varchar"
per tutte queste table.Column<string>
. Quando viene fornito questo parametro, maxLength
e alcuni altri parametri vengono ignorati dal generatore SQL di migrazione. Poiché si suppone che il type
sia il tipo di database effettivo, incluse la dimensione e altri vincoli, ad esempio varchar(100)
ecc. Quando è solo varchar
, SqlServer DDL lo considera come varchar(1)
.
Detto questo, la domanda è che cosa sta causando l'inclusione di quel parametro. Per convenzione non è incluso (ma il tipo di database associato è nvarchar(maxLength)
), quindi deve essere specificato nei mapping del modello.
Avrebbe potuto essere fatto in due modi.
Il primo è applicando l'annotazione dei dati [Column(TypeName ="varchar")]
. Tuttavia, se lo fai, otterrai un'eccezione quando provi a generare una migrazione simile a questa
Il tipo di dati 'varchar' non è supportato in questo modulo. Specificare la lunghezza esplicitamente nel nome del tipo, ad esempio come "varchar (16)", oppure rimuovere il tipo di dati e utilizzare API come HasMaxLength per consentire a EF di scegliere il tipo di dati.
Quindi non dovrebbe essere così, ma il secondo modo di usare l'API fluente di .HasColumnType("varchar")
. Quando lo fai, sorprendentemente la migrazione viene generata senza errori e contiene il parametro sopra menzionato. Trovo questo comportamento almeno incoerente: entrambi dovrebbero lanciare o entrambi dovrebbero avere successo.
In ogni caso, la soluzione è di inserire la lunghezza massima all'interno del nome del tipo, ad es
.HasColumnType("varchar(100)")
o meglio evitare .HasColumnType
dove possibile. Ad esempio, se la string
è mappata su varchar
o nvarchar
dipende isUnicode
che è true
per impostazione predefinita. Quindi, per ottenere il tipo di database varchar(maxLength)
desiderato, sostituire tutto
.HasColumnType("varchar")
nel tuo OnModelCreating
con
.IsUnicode(false)
e lasciare che le chiamate esistenti .HasMaxLenght
gestiscano la lunghezza massima. E non dimenticare di rigenerare la migrazione.
Informazioni sul code
IsUnicode (falso) code
nel mio code
Il code
OnModelCreating non ha funzionato.
builder.Property(fornecedor => fornecedor.Nome)
.IsRequired()
.HasColumnType("varchar")
.IsUnicode(false)
.HasMaxLength(Fornecedor.TamanhoNome);
Sono stato in grado di risolvere il problema in questo modo
builder.Property(fornecedor => fornecedor.Nome)
.IsRequired()
.HasColumnType($"varchar({Fornecedor.TamanhoNome})");
//.IsUnicode(false)
//.HasMaxLength(Fornecedor.TamanhoNome);
Quale risulta in
IdSistemaAntigo = table.Column<string>(type: "varchar(32)", nullable: false),