【问题标题】:nHibernate Euro symbol € change for character ¿nHibernate 欧元符号 € 字符 ¿ 变化
【发布时间】:2025-12-22 19:25:06
【问题描述】:

我尝试在数据库 Oracle 11g 中使用 NHibernate 和 FluentNHibernate 保存欧元符号

我检查了 NHibernate 的日志并查看了生成的 sql 语句:

UPDATE CURRENCY
SET    DESCRIPTION = 'Euro',
       SYMBOL = '€',
WHERE  ID = 63

当执行来自表CURRENCY的查询时,列SYMBOL返回¿

我尝试使用 AnsiString 更改列 SYMBOL 的 FluentNHibernate 映射,如下所示:

Map((x) => x.Symbol).Column("SYMBOL").CustomType("AnsiString").Not.Nullable();

但它不起作用。

我也尝试更改 NVARCHAR2 的列类型并将 FluentNHibernate 映射更改为:

Map((x) => x.Symbol).Column("SYMBOL").CustomSqlType("NVARCHAR2").Not.Nullable();

但它也不起作用。

我怎样才能让它工作?

【问题讨论】:

  • 我可能没有很好地表达自己,但是当我在符号列中保存时,我的问题就出现了,在表格中,字符 ¿ 以这种方式保存,我希望您保存 € 字符。
  • .NET 字符串是 Unicode。您正在尝试将 Unicode 字符串保存到具有某些未知代码页的 ASCII 字段中。无法映射到该代码页的 Unicode 字符将被替换为错误字符。将 字段的 类型更改为 NARCHAR2,并且不要指定 CustomType。

标签: c# .net nhibernate fluent-nhibernate ascii


【解决方案1】:

如果您的应用程序中的所有字符串都是 NVARCHAR2,则您可以将 NVARCHAR2 用于数据库中的所有字符串(否则您可能会因为转换为 VARCHAR2 而遇到性能问题) - 但您至少需要 NHibernate 5.0。在 NHibernate 配置中将此属性设置为 true:oracle.use_n_prefixed_types_for_unicode

nHibernateConfig.SetProperty("oracle.use_n_prefixed_types_for_unicode", "true");

如果您混合了 VARCHAR2 和 NVARCHAR2 列,更好的解决方案是为 NVARCHAR2 列/属性使用自定义类型:

public class UnicodeStringType : IUserType
{
    public bool Equals(object x, object y)
    {
        if (ReferenceEquals(x, y)) return true;
        if (x == null || y == null) return false;
        return x.Equals(y);
    }

    public int GetHashCode(object x)
    {
        return x.GetHashCode();
    }

    public object NullSafeGet(IDataReader rs, string[] names, object owner)
    {
        var value = NHibernateUtil.String.NullSafeGet(rs, names[0]) as string;
        return value;
    }

    public void NullSafeSet(IDbCommand cmd, object value, int index)
    {
        var parameter = (IDataParameter)cmd.Parameters[index];
        ((OracleParameter)parameter).OracleDbType = OracleDbType.NVarchar2;
        parameter.Value = value;
    }

    public object DeepCopy(object value)
    {
        return value;
    }

    public object Replace(object original, object target, object owner)
    {
        return original;
    }

    public object Assemble(object cached, object owner)
    {
        return DeepCopy(cached);
    }

    public object Disassemble(object value)
    {
        return DeepCopy(value);
    }

    public SqlType[] SqlTypes => new[] { new SqlType(DbType.String) };
    public Type ReturnedType => typeof(string);
    public bool IsMutable => false;
}

你在映射中这样使用它:

Map((x) => x.Symbol).Column("SYMBOL").CustomType<UnicodeStringType>().Not.Nullable();

【讨论】: