【问题标题】:Entity Framework Core incorrect field sizeEntity Framework Core 字段大小不正确
【发布时间】:2019-01-23 14:48:51
【问题描述】:

我正在开发一个带有实体框架核心和 SQL Server 2017 Express Edition 的 dotnet core 2.1 应用程序。我创建了迁移并进行了更新,一切都很顺利,但是,在查询数据库时,我注意到字段的大小没有根据迁移应用。

如何在迁移中解决此问题?

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

Migration field size incorrect

这是我的迁移课程

        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
    }

这是我的实体

    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() { }
}

【问题讨论】:

  • type: "varchar" 来自哪里?我的意思是,您是手动添加的还是由添加迁移命令生成的?能贴出实体和流利的配置吗?
  • 迁移类中添加了varchar类型。
  • 好的,我从更新中看到它们来自.HasColumnType("varchar") fluent 配置。

标签: c# entity-framework-core entity-framework-core-2.1


【解决方案1】:

问题在于所有这些table.Column&lt;string&gt; 调用的type: "varchar" 参数。提供此参数时,迁移 SQL 生成器将忽略 maxLength 和其他一些参数。因为type应该是实际的数据库类型,包括大小和其他约束,例如varchar(100)等。当它只是varchar时,SqlServer DDL将其视为varchar(1)

话虽如此,问题是导致包含该参数的原因。按照惯例,它不包括在内(但映射的数据库类型是nvarchar(maxLength)),因此必须在模型映射中指定。

这可以通过两种方式完成。

首先是通过应用[Column(TypeName ="varchar")] 数据注释。但是,如果这样做,在尝试生成类似于此的迁移时会出现异常

此表单不支持数据类型“varchar”。要么在类型名称中明确指定长度,例如“varchar(16)”,要么删除数据类型并使用 HasMaxLength 等 API 来允许 EF 选择数据类型。

所以不应该是这种方式,而是使用.HasColumnType("varchar")fluent API 的第二种方式。当您这样做时,令人惊讶的是,迁移生成时没有任何错误,并且包含上述参数。我发现这种行为至少不一致 - 两者都应该抛出或都应该成功。

无论如何,解决方案是将最大长度放在类型名称中,例如

.HasColumnType("varchar(100)")

或者尽可能避免.HasColumnType。例如,string 是否映射到varcharnvarchar 取决于isUnicode 属性,默认为true。因此,要获得所需的 varchar(maxLength) 数据库类型,请全部替换

.HasColumnType("varchar")

在你的OnModelCreating

.IsUnicode(false)

让现有的.HasMaxLenght 调用处理最大长度。并且不要忘记重新生成迁移。

【讨论】:

  • 您好 Ivan Stoev,感谢您的帮助。我确信 Entity Framework Core 中存在错误。当我使用以下命令运行迁移时,会生成包含类型和大小信息的数据库创建脚本。
  • IsUnicode(false) 确实有效。请注意,您必须删除 .HasColumnType("varchar") 调用(或将它们替换.IsUnicode(false),如答案中所述)。
【解决方案2】:

关于code.IsUnicode(false)code 在我的codeOnModelCreatingcode 不起作用。

builder.Property(fornecedor => fornecedor.Nome)
.IsRequired()
.HasColumnType("varchar")
.IsUnicode(false)
.HasMaxLength(Fornecedor.TamanhoNome);

我可以通过这种方式解决问题

builder.Property(fornecedor => fornecedor.Nome)
.IsRequired()
.HasColumnType($"varchar({Fornecedor.TamanhoNome})");
//.IsUnicode(false)
//.HasMaxLength(Fornecedor.TamanhoNome);

结果

IdSistemaAntigo = table.Column<string>(type: "varchar(32)", nullable: false),

【讨论】:

    猜你喜欢
    • 2021-02-02
    • 2021-02-12
    • 2021-03-05
    • 2019-12-15
    • 2023-01-14
    • 1970-01-01
    • 2021-02-13
    • 2018-12-29
    • 1970-01-01
    相关资源
    最近更新 更多