C# NHibernate与Oracle PL/SQL:含变音符号字符串长度不一致问题
NHibernate存入Oracle VARCHAR(255)列时字符长度异常问题
问题场景
尝试使用NHibernate的ISession对象,将以下字符串存入Oracle数据库的VARCHAR(255)列:
abssssssssssssssssssssssssd RRRRRRRRRRRRRRRAAAAAAAAAAAAAAAąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąąassssssssssssssssss ansssssssssssssssssssssssssssssssssssssssssssssssssssssss ssssssssssssssssssssss
异常现象
- 应用层检查
string.Length,结果为预期的255。 - 执行以下数据库查询验证长度,返回结果也为255:
const string lengthCheckSql = @"SELECT LENGTH(:valueToCheck) as charCount FROM DUAL"; var result = _session.CreateSQLQuery(lengthCheckSql) .AddScalar("charCount", NHibernateUtil.Int32) .SetString("valueToCheck", valueToCheck) .UniqueResult<int>();
- 但调用ISession的Save方法时,数据库抛出异常:字符串长度超过允许值(当前:352,允许:255)。
- 将字符
ą替换为a后,保存操作正常执行。
问题原因
核心是字符数与字节数的统计差异:
- Oracle的
VARCHAR(255)是按字节数限制存储容量,而非字符数。 ą属于扩展Unicode字符,在Oracle默认的AL32UTF8字符集中每个占2个字节,而普通英文字母仅占1个字节。你的字符串中包含大量ą,总字节数=(普通字符数×1)+(ą的数量×2)=352,超过了VARCHAR(255)的字节限制。- 你用的
LENGTH()函数是统计字符数,所以返回255;若要查看真实字节数,需改用Oracle的LENGTHB()函数。 - NHibernate本身没有做特殊编码转换,只是按数据库连接的字符集(通常为UTF8)传递字符串,导致扩展字符的字节数被计入总长度,触发数据库的字节数限制。
解决方法
- 修改数据库列类型:将列类型从
VARCHAR(255)改为VARCHAR2(255 CHAR),这样列的限制改为按字符数计算,255个任意字符都可存入。 - 应用层字节数校验:针对Oracle使用的字符集,在保存前计算字符串的字节长度,若超过255字节则进行截断或提示用户。
- NHibernate映射配置:在实体类的字符串属性映射中,明确指定长度按字符数(需结合NHibernate版本和Oracle方言配置)。
内容的提问来源于stack exchange,提问作者DawDiag
相关产品推荐
相关产品推荐

