Pomelo.EntityFrameworkCore.MySql 访问时出现问题 属性

Pomelo.EntityFrameworkCore.MySql problem when access property

今天我使用 MySql 数据库将我的项目迁移到 .NET 6。 我第一次尝试 Pomelo.EntityFrameworkCore.MySql 但出现了几个错误。 我修复了其中一些,但最后一个,我做不到。

System.InvalidOperationException: The property 'SqlClass.Disabled' is of type 'byte' which is not supported by the current database provider. Either change the property CLR type, or ignore the property using the '[NotMapped]' attribute or by using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'.

             entity.Property(e => e.Disabled)
           //.HasConversion<int>()
            .IsRequired()
            .HasMaxLength(255)
            .HasColumnName("disabled")
            .HasColumnType("tinyint(1)");

    [Required]
    [MaxLength(255)]
    public byte Disabled { get; set; }

有什么想法吗?谢谢。

基本上有 3 个简单的选项,所有选项都在这里用 IceCream.Available 属性:

进行了演示

1。使用 System.Boolean 而不是 System.Byte

Pomelo 默认将 tinyint(1) 翻译成 System.Boolean。因此,如果您将 属性 的 CLR 类型从 byte 更改为 bool,它可以开箱即用:

Program.cs

using System.ComponentModel.DataAnnotations;
using System.Diagnostics;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;

namespace IssueConsoleTemplate
{
    public class IceCream
    {
        public int IceCreamId { get; set; }
        public string Name { get; set; }
        
        [Required]
        [Column(TypeName = "tinyint(1)")] // <-- redundant (bool is translated to tinyint(1) by default)
        public bool Available { get; set; } // <-- use bool
    }

    public class Context : DbContext
    {
        public DbSet<IceCream> IceCreams { get; set; }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            var connectionString = "server=127.0.0.1;port=3306;user=root;password=;database=So70198786";
            var serverVersion = ServerVersion.AutoDetect(connectionString);

            optionsBuilder
                .UseMySql(connectionString, serverVersion)
                .UseLoggerFactory(
                    LoggerFactory.Create(
                        b => b
                            .AddConsole()
                            .AddFilter(level => level >= LogLevel.Information)))
                .EnableSensitiveDataLogging()
                .EnableDetailedErrors();
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<IceCream>(
                entity =>
                {
                    // Not needed if you are using data annotations:
                    //
                    // entity.Property(e => e.Available)
                    //     .IsRequired()
                    //     .HasColumnType("tinyint(1)"); // <-- redundant (bool is translated to tinyint(1) by default)

                    entity.HasData(
                        new IceCream
                        {
                            IceCreamId = 1,
                            Name = "Vanilla",
                            Available = true, // <-- bool
                        },
                        new IceCream
                        {
                            IceCreamId = 2,
                            Name = "Chocolate",
                            Available = false, // <-- bool
                        });
                });
        }
    }

    internal static class Program
    {
        private static void Main()
        {
            using var context = new Context();

            context.Database.EnsureDeleted();
            context.Database.EnsureCreated();

            var availableIceCreams = context.IceCreams
                .Where(i => i.Available) // <-- bool
                .ToList();
            
            Trace.Assert(availableIceCreams.Count == 1);
            Trace.Assert(availableIceCreams[0].Name == "Vanilla");
        }
    }
}

输出(SQL)

warn: Microsoft.EntityFrameworkCore.Model.Validation[10400]
      Sensitive data logging is enabled. Log entries and exception messages may include sensitive application data; this mode should only be enabled during development.
info: Microsoft.EntityFrameworkCore.Infrastructure[10403]
      Entity Framework Core 6.0.0 initialized 'Context' using provider 'Pomelo.EntityFrameworkCore.MySql:6.0.0-rtm.1' with options: ServerVersion 8.0.25-mysql SensitiveDataLoggingEnabled DetailedErrorsEnabled
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (38ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      DROP DATABASE `So70198786`;
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (13ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      CREATE DATABASE `So70198786`;
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (15ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      ALTER DATABASE CHARACTER SET utf8mb4;
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (47ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      CREATE TABLE `IceCreams` (
          `IceCreamId` int NOT NULL AUTO_INCREMENT,
          `Name` longtext CHARACTER SET utf8mb4 NULL,
          `Available` tinyint(1) NOT NULL,
          CONSTRAINT `PK_IceCreams` PRIMARY KEY (`IceCreamId`)
      ) CHARACTER SET=utf8mb4;
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (9ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      INSERT INTO `IceCreams` (`IceCreamId`, `Available`, `Name`)
      VALUES (1, TRUE, 'Vanilla');
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (10ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      INSERT INTO `IceCreams` (`IceCreamId`, `Available`, `Name`)
      VALUES (2, FALSE, 'Chocolate');
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (5ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      SELECT `i`.`IceCreamId`, `i`.`Available`, `i`.`Name`
      FROM `IceCreams` AS `i`
      WHERE `i`.`Available`

2。使用 tinyint 而不是 tinyint(1)

如果您确定要使用 System.Byte 作为 属性 的 CLR 类型,请使用 tinyint 而不是 tinyint(1)。默认情况下,除 tinyint(1) 外的所有 tinyint 都翻译为 System.Byte

Program.cs

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Diagnostics;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;

namespace IssueConsoleTemplate
{
    public class IceCream
    {
        public int IceCreamId { get; set; }
        public string Name { get; set; }
        
        [Required]
        [Column(TypeName = "tinyint")] // <-- redundant (byte is translated to tinyint by default)
        public byte Available { get; set; }
    }

    public class Context : DbContext
    {
        public DbSet<IceCream> IceCreams { get; set; }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            var connectionString = "server=127.0.0.1;port=3306;user=root;password=;database=So70198786_01";
            var serverVersion = ServerVersion.AutoDetect(connectionString);

            optionsBuilder
                .UseMySql(connectionString, serverVersion)
                .UseLoggerFactory(
                    LoggerFactory.Create(
                        b => b
                            .AddConsole()
                            .AddFilter(level => level >= LogLevel.Information)))
                .EnableSensitiveDataLogging()
                .EnableDetailedErrors();
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<IceCream>(
                entity =>
                {
                    // Not needed if you are using data annotations:
                    //
                    // entity.Property(e => e.Available)
                    //     .IsRequired()
                    //     .HasColumnType("tinyint"); // <-- redundant (byte is translated to tinyint by default)

                    entity.HasData(
                        new IceCream
                        {
                            IceCreamId = 1,
                            Name = "Vanilla",
                            Available = 1, // <-- byte
                        },
                        new IceCream
                        {
                            IceCreamId = 2,
                            Name = "Chocolate",
                            Available = 0, // <-- byte
                        });
                });
        }
    }

    internal static class Program
    {
        private static void Main()
        {
            using var context = new Context();

            context.Database.EnsureDeleted();
            context.Database.EnsureCreated();

            var availableIceCreams = context.IceCreams
                .Where(i => i.Available != 0) // <-- byte
                .ToList();
            
            Trace.Assert(availableIceCreams.Count == 1);
            Trace.Assert(availableIceCreams[0].Name == "Vanilla");
        }
    }
}

输出(SQL)

warn: Microsoft.EntityFrameworkCore.Model.Validation[10400]
      Sensitive data logging is enabled. Log entries and exception messages may include sensitive application data; this mode should only be enabled during development.
info: Microsoft.EntityFrameworkCore.Infrastructure[10403]
      Entity Framework Core 6.0.0 initialized 'Context' using provider 'Pomelo.EntityFrameworkCore.MySql:6.0.0-rtm.1' with options: ServerVersion 8.0.25-mysql SensitiveDataLoggingEnabled DetailedErrorsEnabled
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (42ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      DROP DATABASE `So70198786_01`;
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (41ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      CREATE DATABASE `So70198786_01`;
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (19ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      ALTER DATABASE CHARACTER SET utf8mb4;
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (48ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      CREATE TABLE `IceCreams` (
          `IceCreamId` int NOT NULL AUTO_INCREMENT,
          `Name` longtext CHARACTER SET utf8mb4 NULL,
          `Available` tinyint NOT NULL,
          CONSTRAINT `PK_IceCreams` PRIMARY KEY (`IceCreamId`)
      ) CHARACTER SET=utf8mb4;
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (9ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      INSERT INTO `IceCreams` (`IceCreamId`, `Available`, `Name`)
      VALUES (1, 1, 'Vanilla');
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (10ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      INSERT INTO `IceCreams` (`IceCreamId`, `Available`, `Name`)
      VALUES (2, 0, 'Chocolate');
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (6ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      SELECT `i`.`IceCreamId`, `i`.`Available`, `i`.`Name`
      FROM `IceCreams` AS `i`
      WHERE `i`.`Available` <> 0

3。将默认 System.Boolean 映射更改为 bit(1) 或将其完全删除

最后,如果您需要将 tinyint(1) 精确映射到 System.Byte,那么您可以通过设置 DbContext 来更改 Pomelo 用于 System.Boolean 的默认映射UseMySql() 电话中的选项:

Program.cs

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Diagnostics;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Pomelo.EntityFrameworkCore.MySql.Infrastructure;

namespace IssueConsoleTemplate
{
    public class IceCream
    {
        public int IceCreamId { get; set; }
        public string Name { get; set; }
        
        [Required]
        [Column(TypeName = "tinyint(1)")] // <-- necessary (otherwise gets translated to tinyint)
        public byte Available { get; set; }
    }

    public class Context : DbContext
    {
        public DbSet<IceCream> IceCreams { get; set; }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            var connectionString = "server=127.0.0.1;port=3306;user=root;password=;database=So70198786_02";
            var serverVersion = ServerVersion.AutoDetect(connectionString);

            optionsBuilder
                .UseMySql(
                    connectionString,
                    serverVersion,
                    options => options.DefaultDataTypeMappings( // <-- change default data type mappings
                        m => m.WithClrBoolean(MySqlBooleanType.Bit1))) // <-- or even MySqlBooleanType.None
                .UseLoggerFactory(
                    LoggerFactory.Create(
                        b => b
                            .AddConsole()
                            .AddFilter(level => level >= LogLevel.Information)))
                .EnableSensitiveDataLogging()
                .EnableDetailedErrors();
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<IceCream>(
                entity =>
                {
                    // Not needed if you are using data annotations:
                    //
                    // entity.Property(e => e.Available)
                    //     .IsRequired()
                    //     .HasColumnType("tinyint(1)"); // <-- necessary (otherwise gets translated to tinyint)

                    entity.HasData(
                        new IceCream
                        {
                            IceCreamId = 1,
                            Name = "Vanilla",
                            Available = 1, // <-- byte
                        },
                        new IceCream
                        {
                            IceCreamId = 2,
                            Name = "Chocolate",
                            Available = 0, // <-- byte
                        });
                });
        }
    }

    internal static class Program
    {
        private static void Main()
        {
            using var context = new Context();

            context.Database.EnsureDeleted();
            context.Database.EnsureCreated();

            var availableIceCreams = context.IceCreams
                .Where(i => i.Available != 0) // <-- byte
                .ToList();
            
            Trace.Assert(availableIceCreams.Count == 1);
            Trace.Assert(availableIceCreams[0].Name == "Vanilla");
        }
    }
}

输出(SQL)

warn: Microsoft.EntityFrameworkCore.Model.Validation[10400]
      Sensitive data logging is enabled. Log entries and exception messages may include sensitive application data; this mode should only be enabled during development.
info: Microsoft.EntityFrameworkCore.Infrastructure[10403]
      Entity Framework Core 6.0.0 initialized 'Context' using provider 'Pomelo.EntityFrameworkCore.MySql:6.0.0-rtm.1' with options: ServerVersion 8.0.25-mysql SensitiveDataLoggingEnabled DetailedErrorsEnabled
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (40ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      DROP DATABASE `So70198786_02`;
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (13ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      CREATE DATABASE `So70198786_02`;
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (19ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      ALTER DATABASE CHARACTER SET utf8mb4;
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (86ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      CREATE TABLE `IceCreams` (
          `IceCreamId` int NOT NULL AUTO_INCREMENT,
          `Name` longtext CHARACTER SET utf8mb4 NULL,
          `Available` tinyint(1) NOT NULL,
          CONSTRAINT `PK_IceCreams` PRIMARY KEY (`IceCreamId`)
      ) CHARACTER SET=utf8mb4;
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (7ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      INSERT INTO `IceCreams` (`IceCreamId`, `Available`, `Name`)
      VALUES (1, 1, 'Vanilla');
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (3ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      INSERT INTO `IceCreams` (`IceCreamId`, `Available`, `Name`)
      VALUES (2, 0, 'Chocolate');
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (7ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
      SELECT `i`.`IceCreamId`, `i`.`Available`, `i`.`Name`
      FROM `IceCreams` AS `i`
      WHERE `i`.`Available` <> 0

与本题主题无关,[MaxLength(255)].HasMaxLength(255)对非字符串列没有影响