NHibernate:如何将 C# [Guid] 插入 MySQL [BINARY(16) DEFAULT (uuid_to_bin(uuid(),1))] 列?
NHibernate: How to insert C# [Guid] into MySQL [BINARY(16) DEFAULT (uuid_to_bin(uuid(),1))] column?
环境: MySQL 服务器 8.0,.NET Core 3.1,MySql.Data 8.0.28,NHibernate 5.3.11
我关注table:
CREATE TABLE `Master` (
`Row_Id` char(36) NOT NULL DEFAULT (uuid()),
`Path` varchar(1000) NOT NULL,
PRIMARY KEY (`Row_Id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
以下是实体定义和映射:
public class MasterEntity
{
public virtual Guid RowId { get; set; }
public virtual string Path { get; set; }
}
internal sealed class MasterMap : ClassMapping<MasterEntity>
{
public MasterMap()
{
Table("Master");
Id
(
x => x.RowId,
map =>
{
map.Column("Row_Id");
map.Generator(Generators.GuidComb);
}
);
Property(x => x.Path, map => { map.Column("Path"); map.NotNullable(true); map.Type(TypeFactory.GetAnsiStringType(1000)); });
}
}
以下是我如何 INSERT
使用 NHibernate 这个实体:
using(ISession session = SessionFactory.OpenSession())
{
MasterEntity entity = new MasterEntity();
entity.Path = "c:\whatever";
session.Save(entity);
session.Flush();
}
这将正确插入记录。到这里,一切都很好。
现在,我将 Row_Id
列的定义更改如下:
`Row_Id` binary(16) NOT NULL DEFAULT (uuid_to_bin(uuid(),1)),
我没有更改我的 C# 代码中的任何内容。现在,session.Flush();
调用抛出以下异常:
NHibernate.Exceptions.GenericADOException: could not execute batch command.[SQL: SQL not available]
---> MySql.Data.MySqlClient.MySqlException (0x80004005): Data too long for column 'Row_Id' at row 1
错误看起来很明显。 C#中的Guid
为32,列长为16。
我需要在映射或实体定义(或代码的其他部分)中进行哪些更改才能将 C# Guid
插入 BINARY(16) DEFAULT (uuid_to_bin(uuid(),1))
列?
默认情况下,MySql.Data 会将 Guid
存储为 CHAR(36)
。您可以通过在连接字符串中指定 Old Guids = True;
来使用 BINARY(16)
。
来自Connector/NET 8.0 Connection Options Reference:
The back-end representation of a GUID type was changed from BINARY(16)
to CHAR(36)
. This was done to allow developers to use the server function UUID()
to populate a GUID table - UUID()
generates a 36-character string. Developers of older applications can add 'Old Guids=true'
to the connection string to use a GUID of data type BINARY(16)
.
中建议的方式有效;但它有一个问题。
题中代码使用uuid_to_bin(uuid(),1)
;第二个 swap
参数设置为 1
。有了这个,INSERT 工作得很好;但是当你 SELECT 该行时,你会得到完全不同的 UUID。这是因为,数据库驱动程序不知道 UUID 是否被交换。
更好的解决方案是使用 MySqlConnector
而不是 Oracle 的 Connector/NET (MySql.Data.dll).
对于ADO.NET:
按照说明进行配置 here。
For .NET Core 2.1 or later, call DbProviderFactories.RegisterFactory("MySqlConnector", MySqlConnectorFactory.Instance)
during application startup. This will register MySqlConnector’s DbProviderFactory
implementation in the central DbProviderFactories
registry.
我的观察是,不需要调用 DbProviderFactories.RegisterFactory
。它只是通过添加 MySqlConnector.dll 的引用并删除 MySql.Data.dll.
的引用来工作
对于 MySqlConnector
,OldGuids=True;
设置可用但已过时;避免它。
将 GuidFormat=TimeSwapBinary16;
用于 uuid_to_bin(uuid(),1)
(交换参数设置为 1)。
提到了其他可能的值 here:
Determines which column type (if any) should be read as a System.Guid
. The options include:
Char36
:
All CHAR(36)
columns are read/written as a Guid
using lowercase hex with hyphens, which matches UUID()
.
Char32
:
All CHAR(32)
columns are read/written as a Guid
using lowercase hex without hyphens.
Binary16
:
All BINARY(16)
columns are read/written as a Guid
using big-endian byte order, which matches UUID_TO_BIN(x)
.
TimeSwapBinary16
:
All BINARY(16)
columns are read/written as a Guid
using big-endian byte order with time parts swapped, which matches UUID_TO_BIN(x,1)
.
LittleEndianBinary16
:
All BINARY(16)
columns are read/written as a Guid
using little-endian byte order, i.e. the byte order used by Guid.ToByteArray()
and the Guid(byte[])
constructor.
None
:
No column types are automatically read as a Guid
.
Default
:
Same as Char36
if OldGuids=False;
same as LittleEndianBinary16
if OldGuids=True
.
对于 NHibernate:
- 安装
NHibernate.MySqlConnector
from nuget package.
- 在会话工厂配置中添加
configuration.DataBaseIntegration(c => c.MySqlConnectorDriver());
。
- 如上所述在连接字符串中设置
GuidFormat
。
对于其他 ORM:
请参考 this 与其他 ORM 的用法。
环境: MySQL 服务器 8.0,.NET Core 3.1,MySql.Data 8.0.28,NHibernate 5.3.11
我关注table:
CREATE TABLE `Master` (
`Row_Id` char(36) NOT NULL DEFAULT (uuid()),
`Path` varchar(1000) NOT NULL,
PRIMARY KEY (`Row_Id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
以下是实体定义和映射:
public class MasterEntity
{
public virtual Guid RowId { get; set; }
public virtual string Path { get; set; }
}
internal sealed class MasterMap : ClassMapping<MasterEntity>
{
public MasterMap()
{
Table("Master");
Id
(
x => x.RowId,
map =>
{
map.Column("Row_Id");
map.Generator(Generators.GuidComb);
}
);
Property(x => x.Path, map => { map.Column("Path"); map.NotNullable(true); map.Type(TypeFactory.GetAnsiStringType(1000)); });
}
}
以下是我如何 INSERT
使用 NHibernate 这个实体:
using(ISession session = SessionFactory.OpenSession())
{
MasterEntity entity = new MasterEntity();
entity.Path = "c:\whatever";
session.Save(entity);
session.Flush();
}
这将正确插入记录。到这里,一切都很好。
现在,我将 Row_Id
列的定义更改如下:
`Row_Id` binary(16) NOT NULL DEFAULT (uuid_to_bin(uuid(),1)),
我没有更改我的 C# 代码中的任何内容。现在,session.Flush();
调用抛出以下异常:
NHibernate.Exceptions.GenericADOException: could not execute batch command.[SQL: SQL not available]
---> MySql.Data.MySqlClient.MySqlException (0x80004005): Data too long for column 'Row_Id' at row 1
错误看起来很明显。 C#中的Guid
为32,列长为16。
我需要在映射或实体定义(或代码的其他部分)中进行哪些更改才能将 C# Guid
插入 BINARY(16) DEFAULT (uuid_to_bin(uuid(),1))
列?
默认情况下,MySql.Data 会将 Guid
存储为 CHAR(36)
。您可以通过在连接字符串中指定 Old Guids = True;
来使用 BINARY(16)
。
来自Connector/NET 8.0 Connection Options Reference:
The back-end representation of a GUID type was changed from
BINARY(16)
toCHAR(36)
. This was done to allow developers to use the server functionUUID()
to populate a GUID table -UUID()
generates a 36-character string. Developers of older applications can add'Old Guids=true'
to the connection string to use a GUID of data typeBINARY(16)
.
题中代码使用uuid_to_bin(uuid(),1)
;第二个 swap
参数设置为 1
。有了这个,INSERT 工作得很好;但是当你 SELECT 该行时,你会得到完全不同的 UUID。这是因为,数据库驱动程序不知道 UUID 是否被交换。
更好的解决方案是使用 MySqlConnector
而不是 Oracle 的 Connector/NET (MySql.Data.dll).
对于ADO.NET:
按照说明进行配置 here。
For .NET Core 2.1 or later, call
DbProviderFactories.RegisterFactory("MySqlConnector", MySqlConnectorFactory.Instance)
during application startup. This will register MySqlConnector’sDbProviderFactory
implementation in the centralDbProviderFactories
registry.
我的观察是,不需要调用 DbProviderFactories.RegisterFactory
。它只是通过添加 MySqlConnector.dll 的引用并删除 MySql.Data.dll.
对于 MySqlConnector
,OldGuids=True;
设置可用但已过时;避免它。
将 GuidFormat=TimeSwapBinary16;
用于 uuid_to_bin(uuid(),1)
(交换参数设置为 1)。
提到了其他可能的值 here:
Determines which column type (if any) should be read as a
System.Guid
. The options include:
Char36
:
AllCHAR(36)
columns are read/written as aGuid
using lowercase hex with hyphens, which matchesUUID()
.
Char32
:
AllCHAR(32)
columns are read/written as aGuid
using lowercase hex without hyphens.
Binary16
:
All BINARY(16)
columns are read/written as aGuid
using big-endian byte order, which matchesUUID_TO_BIN(x)
.
TimeSwapBinary16
:
AllBINARY(16)
columns are read/written as aGuid
using big-endian byte order with time parts swapped, which matchesUUID_TO_BIN(x,1)
.
LittleEndianBinary16
:
AllBINARY(16)
columns are read/written as aGuid
using little-endian byte order, i.e. the byte order used byGuid.ToByteArray()
and theGuid(byte[])
constructor.
None
:
No column types are automatically read as aGuid
.
Default
:
Same asChar36
ifOldGuids=False;
same asLittleEndianBinary16
ifOldGuids=True
.
对于 NHibernate:
- 安装
NHibernate.MySqlConnector
from nuget package. - 在会话工厂配置中添加
configuration.DataBaseIntegration(c => c.MySqlConnectorDriver());
。 - 如上所述在连接字符串中设置
GuidFormat
。
对于其他 ORM:
请参考 this 与其他 ORM 的用法。