Reputation: 21
Today I migrate my project to .NET 6 with MySql db. I tried Pomelo.EntityFrameworkCore.MySql for the first time but several errors had occur. I fixed some of them but the last one, I couldn`t.
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; }
Any ideas ? Thank you.
Upvotes: 0
Views: 4047
Reputation: 5254
There are basically 3 simple options, all demonstrated here with the IceCream.Available
property:
System.Boolean
instead of System.Byte
Pomelo translates tinyint(1)
to System.Boolean
by default. So if you change the CLR type of your property from byte
to bool
, it works out-of-the box:
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");
}
}
}
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`
tinyint
instead of tinyint(1)
In case you definitely want to use System.Byte
as the CLR type of your property, use tinyint
instead of tinyint(1)
. All tinyint
except tinyint(1)
are translated to System.Byte
by default:
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");
}
}
}
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
System.Boolean
mapping to bit(1)
or remove it altogetherFinally, if you need to map exactly tinyint(1)
to System.Byte
, then you can change the default mapping that Pomelo is using for System.Boolean
by setting a DbContext
option in your UseMySql()
call:
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");
}
}
}
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
Unrelated to the topic of this question, [MaxLength(255)]
or .HasMaxLength(255)
have no effect on non-string columns.
Upvotes: 1