关于 Guid 类型的映射

MySql 没有原生的 Guid 类型,一般使用 binary(16) 或者 char(36) 这两个类型。早期版本的 Connector/Net 将 binary(16) 自动映射成为 Guid 类型。从 Connector/Net 6.1.1 开始,binary(16) 不再被自动映射成为 Guid 类型,而选用 char(36)。通过连接字符串的 Old Guids = true 选项可使用旧的 binary(16) 映射,这个选项的缺省值是 false,即使用 char(36)。参考 21.2.6. Connector/NET Connection String Options Reference

string connectionString = "server=localhost;user id=user;password=pwd;database=db;character set=utf8;Old Guids=true";

遗憾的是,在最新的发布版本 Connector/Net 6.2.3 中,缺少像 Treat Tiny As Boolean=false 这样的开关,无法关闭从 char(36) 到 Old Guid 的自动映射。因此,当你的数据库中恰巧使用了 char(36) 这个类型且这个字段存了不是合法 Guid 格式的字符值(中间用短横线隔开的 32 个数字 ,即 xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx),那么你的程序就会报错。空字符是一个常见的情况,我们最近的一个系统就是被这个害惨了。虽然,我们明确这个 char(36) 类型字段是存应用程序生成的 Guid,而且加了 NOT NULL 约束,但在其他应用程序(PHP实现)中由于种种不可修复的原因,偶尔会向这个字段入了空字符,导致现有应用程序(.NET实现)读取失败。更要命的是,这个错误是在 MySqlDataReader.Read() 方法发生的,异常堆栈如下:

System.FormatException: Guid should contain 32 digits with 4 dashes (xxxxxxxx-xx
xx-xxxx-xxxx-xxxxxxxxxxxx).
   at System.Guid..ctor(String g)
   at MySql.Data.Types.MySqlGuid.MySql.Data.Types.IMySqlValue.ReadValue(MySqlPac
ket packet, Int64 length, Boolean nullVal) in E:\MySQL\mysql-connector-net-6.2.3
-src\MySql.Data\Provider\Source\Types\MySqlGuid.cs:line 234
   at MySql.Data.MySqlClient.NativeDriver.ReadColumnValue(Int32 index, MySqlFiel
d field, IMySqlValue valObject) in E:\MySQL\mysql-connector-net-6.2.3-src\MySql.
Data\Provider\Source\NativeDriver.cs:line 648
   at MySql.Data.MySqlClient.Driver.ReadColumnValue(Int32 index, MySqlField fiel
d, IMySqlValue value) in E:\MySQL\mysql-connector-net-6.2.3-src\MySql.Data\Provi
der\Source\Driver.cs:line 415
   at MySql.Data.MySqlClient.ResultSet.ReadColumnData(Boolean outputParms) in E:
\MySQL\mysql-connector-net-6.2.3-src\MySql.Data\Provider\Source\ResultSet.cs:lin
e 272
   at MySql.Data.MySqlClient.ResultSet.NextRow(CommandBehavior behavior) in E:\M
ySQL\mysql-connector-net-6.2.3-src\MySql.Data\Provider\Source\ResultSet.cs:line
210
   at MySql.Data.MySqlClient.MySqlDataReader.Read() in E:\MySQL\mysql-connector-
net-6.2.3-src\MySql.Data\Provider\Source\datareader.cs:line 875
   at LeoLab.MySql.GuidChar36Test.Program.Main(String[] args) in E:\LeoLab.MySql
\LeoLab.MySql.GuidChar36Test\LeoLab.MySql.GuidChar36Test\Program.cs:line 30

这个错误信息中没有包含是哪一列哪一行发生了错误,因此,当你的 SELECT 语言包含很多字段,结果集又比较大的时候,就晕菜了,不知道这个 char(36) 与 Guid 映射关系的就被搞得莫名其妙的了。

目前最快速的解决方法,是“曲线救国”:通过设置 Old Guids=true 启用 binary(16) 到 guid 的映射来间接禁用 char(36) 到 Guid 的映射。

此外,我修改了 Connector/Net 6.2.3 的源码,增加了一个类似 Treat Tiny As Boolean 的 Treat Char As Guid 选项类禁用 char(36) 到 Guid 的映射。大概修改如下:

1. MySqlConnectionStringBuilder 中增加属性 TreatCharAsGuid

01.[Category("Advanced")] 
02.[DisplayName("Treat Char As Guid")] 
03.[Description("Should the provider treat CHAR(36) columns as Guid.")] 
04.[DefaultValue(true)] 
05.[ValidKeywords("Treat Char As Guid")] 
06.[RefreshProperties(RefreshProperties.All)] 
07.public bool TreatCharAsGuid 
08.
09.    get { return (bool)values["Treat Char As Guid"]; } 
10.    set { SetValue("Treat Char As Guid", value); } 
11.}

2. MySqlField 类的 SetTypeAndFlags 方法中的判断 if (Type == MySqlDbType.String && CharacterLength == 36 && !driver.Settings.OldGuids) 中增加TreatCharAsGuid的判断

1.if (driver.Settings.TreatCharAsGuid && Type == MySqlDbType.String && CharacterLength == 36 && !driver.Settings.OldGuids) 
2.            
3.                mySqlDbType = MySqlDbType.Guid; 
4.            }

这样我们在连接字符串中指定 Treat Char As Guid=false,char(36) 就不会被映射成为 Guid 了,而是普通 String 。

源码下载 MySqlConnectorNet6.2.3-TreatCharAsGuid.zip (308.80 kb)

可遇不可求的Question之MySqlClient的Guid 类型的映射篇的更多相关文章

  1. 可遇不可求的Question之导入mysql中文乱码解决方法篇

    可遇不可求的Question之导入mysql中文乱码解决方法篇 先 set names utf8;然后 source c:\1.sql ?

  2. 可遇不可求的Question之INSERT … ON DUPLICATE KEY UPDATE 语法篇

    MySQL 自4.1版以后开始支持INSERT … ON DUPLICATE KEY UPDATE语法,使得原本需要执行3条SQL语句(SELECT,INSERT,UPDATE),缩减为1条语句即可完 ...

  3. 可遇不可求的Question之flash的socket连接安全策略文件篇

    flash的socket连接安全策略文件   最近公司做压力测试的时候,发现了一个问题.flash的socket客户端向服务端请求安全策略文件的时候,服务端负责回发策略文件的端口能连接上,但是没有响应 ...

  4. 可遇不可求的Question之MySQL系统变量interactive_timeout 与 wait_timeout 篇

    mysql>show variables like '%timeout'; 打印结果如下: +----------------------------+-------+ | Variable_n ...

  5. 可遇不可求的Question之MySql4.0前版本不支持union与批量SQL提交

    批量SQL提交 参考 21.2.6. Connector/NET Connection String Options Reference . Allow Batch true When true, m ...

  6. 可遇不可求的Question之SQLSERVER触发器不支持多行插入操作篇

    描述: 我们经常遇到 insert table_a select * from table_b 这样的语句, 同时在表table_a中根据每一条新增的SQL语句,通过触发器来触发对应的一系列的后续操作 ...

  7. 可遇不可求的Question之Sqlserver2005文件组的迁移篇

    Sqlserver2005 文件组的折腾 问题:由于数据庞大,我在数据库里面使用了分区表,建了很多文件组,一个分区对应一个文件组,一个文件组只有一个文件.我在建分区表的时候,在数据库属性里面“文件”选 ...

  8. 可遇不可求的Question之Mysql在不重启服务的情况下修改运行时变量篇

    比方说在一些实际生产环境中,想改个MYSQL的配置,但是又不想停止服务重起MYSQL,有什么办法呢?使用SET命令可以做到,请看下面几个例子: 1.设置key_buffer_size的大小为10M. ...

  9. 可遇不可求的Question之error: Failed dependencies: MySQLconflicts 错误篇

    error: Failed dependencies: MySQLconflicts   错误提示: error: Failed dependencies:                       ...

随机推荐

  1. (项目六)Mha-Atlas-MySQL高可用方案实践

    mha-mysql环境准备: 三台虚拟机,都安装了mysql,都关闭防火墙和selinux,同时在每台虚拟机上都做映射 软件包 1) mha管理节点安装包: mha4mysql-manager-0.5 ...

  2. Codeforces Round #442 (Div. 2) E Danil and a Part-time Job (dfs序加上一个线段树区间修改查询)

    题意: 给出一个具有N个点的树,现在给出两种操作: 1.get x,表示询问以x作为根的子树中,1的个数. 2.pow x,表示将以x作为根的子树全部翻转(0变1,1变0). 思路:dfs序加上一个线 ...

  3. ApplicationListener接口的生命周期

    create:游戏初次创建时被调用,一般在这里创建ApplicationListener对象,初始化布景信息,将数据或UI布局绑定到监听器等,执行完该方法后会执行resize方法,是游戏创建立即执行的 ...

  4. angularJS+KindEditor无法获取或清空textarea的值

    在html页面中初始化KindEditor: <script type="text/javascript"> var editor; KindEditor.ready( ...

  5. model 字段参数 choice

    class Banner(NewsBase): ''' 轮播图 ''' PRI_CHOICES = [ # 优先级的限制选择范围 (1,'第一级'), (2,'第二级'), (3,'第三级'), (4 ...

  6. C# 截取两个指定字符串中间的字符串列表

    /// <summary> /// 截取两个指定字符串中间的字符串列表(开始和结束两个字符串不能相同!) /// </summary> /// <param name=& ...

  7. python jieba 库分词结合Wordcloud词云统计

    import jieba jieba.add_word("福军") jieba.add_word("少安") excludes={"一个", ...

  8. pythone函数基础(13)发送网络请求

    需要导入urllib模块,request模块发送网络请求有两种方法 第一种方法# from urllib.request import urlopen# from urllib.parse impor ...

  9. webpack 模块方法

    1. webpack的import和export不需要引入babel 其他ES6语法需要引入babel 2. import引入export导出的模块 3. import()模块分离  低版本浏览器想使 ...

  10. python websocket 再线聊天室的 Demo

    服务端 import tornado.web import tornado.ioloop import tornado.httpserver import tornado.options import ...