NHibernate:如何将 C# [Guid] 插入 MySQL [BINARY(16) DEFAULT (uuid_to_bin(uuid(),1))] 列?
环境: MySQL Server 8.0、.NET Core 3.1、MySql.Data 8.0.28、NHibernate 5.3.11
我有下表:
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< /code> 该实体使用 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))< /代码> 列?
Environment: MySQL Server 8.0, .NET Core 3.1, MySql.Data 8.0.28, NHibernate 5.3.11
I have following 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;
Following is entity definition and mapping:
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)); });
}
}
Following is how I INSERT
this entity using NHibernate:
using(ISession session = SessionFactory.OpenSession())
{
MasterEntity entity = new MasterEntity();
entity.Path = "c:\whatever";
session.Save(entity);
session.Flush();
}
This inserts the record correctly. Up to here, everything is fine.
Now, I change the definition of Row_Id
column as below:
`Row_Id` binary(16) NOT NULL DEFAULT (uuid_to_bin(uuid(),1)),
I do not change anything in my C# code. Now, the session.Flush();
call throws below exception:
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
The error looks obvious. The Guid
in C# is 32 and column length is 16.
What changes I need to make in my mapping or entity definition (or other part of code) to insert C# Guid
into BINARY(16) DEFAULT (uuid_to_bin(uuid(),1))
column?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
默认情况下,MySql.Data 会将
Guid
存储为CHAR(36)
。您可以通过在连接字符串中指定Old Guids = True;
来使用BINARY(16)
。来自 连接器/NET 8.0 连接选项参考:
By default, MySql.Data will store a
Guid
asCHAR(36)
. You can useBINARY(16)
instead by specifyingOld Guids = True;
in your connection string.From Connector/NET 8.0 Connection Options Reference:
接受的答案中建议的方式有效;但它有一个问题。
问题中的代码使用
uuid_to_bin(uuid(),1)
;第二个swap
参数设置为1
。这样,INSERT 就可以很好地工作了;但是当您选择该行时,您会得到完全不同的 UUID。这是因为,数据库驱动程序不知道 UUID 是否被交换。更好的解决方案是使用
MySqlConnector
而不是 Oracle 的 Connector/NET (MySql.Data.dll )。对于 ADO.NET:
按照此处的说明进行配置。
我的观察是,不需要调用
DbProviderFactories.RegisterFactory
。它只是通过添加 MySqlConnector.dll 的引用并删除 MySql.Data.dll 的引用来工作。使用
MySqlConnector
,OldGuids=True;
设置可用,但过时的;避免它。使用
GuidFormat=TimeSwapBinary16;
表示uuid_to_bin(uuid(),1)
(交换参数设置为 1)。此处提到了其他可能的值:
对于NHibernate:
NHibernate.MySqlConnector
来自 nuget 包。configuration.DataBaseIntegration(c => c.MySqlConnectorDriver());
。GuidFormat
。对于其他ORM:
使用请参考此与其他 ORM 一起使用。
The way suggested in accepted answer works; but it has a problem.
The code in the question uses
uuid_to_bin(uuid(),1)
; the secondswap
parameter is set to1
. With this, the INSERT works great; but when you SELECT the row, you get entirely different UUID. This is because, database drivers do not know whether the UUID is swapped or not.Better solution is to use
MySqlConnector
instead of Oracle's Connector/NET (MySql.Data.dll).For ADO.NET:
Configure it as explained here.
My observation is that, call to
DbProviderFactories.RegisterFactory
is not needed. It just works by adding reference of MySqlConnector.dll and removing reference of MySql.Data.dll.With
MySqlConnector
, theOldGuids=True;
setting is available but obsolete; avoid it.Use
GuidFormat=TimeSwapBinary16;
foruuid_to_bin(uuid(),1)
(swap parameter set to 1).Other possible values are mentioned here:
For NHibernate:
NHibernate.MySqlConnector
from nuget package.configuration.DataBaseIntegration(c => c.MySqlConnectorDriver());
in Session Factory configuration.GuidFormat
in connection string as explained above.For other ORMs:
Please refer to this for usage with other ORMs.