1

我正在尝试让 Informix 在 Windows 7 上与 NHibernate 一起工作。我有一个连接字符串现在可以与 informix 一起正常工作,就是这样,

Database=db;Server=server:port;uid=username;password=password;pooling=false

我正在使用 IBM.Data.Informix .NET 提供程序版本 9.0.0.2。

我们有许多不同的应用程序在使用这个提供程序和我们正在运行的 Informix 服务器时可以正常工作。

我的 nhibernate 应用程序现在正在连接到 informix 服务器,但问题是它生成的 SQL 的形式。

如果我的休眠代码如下所示,

using (ISession session = Config.SessionFactory.OpenSession())
{
    return session
        .CreateCriteria<DBTable>()
        .Add(Restrictions.Eq("FieldValue", true))
        .List<DBTable>();
}

我是 Informix 的新手,但如果我没记错的话,正确的 SQL 应该是这样,

从 DBTable 中选择 *,其中 fieldValue = 'T'

但相反,它产生的 SQL 是,

select * from DBTable where fieldValue = True

这是行不通的。我尝试将这样的东西添加到 nhibernate 配置文件中,

<property name="query.substitutions">True=T,False=F</property>
<property name="query.substitutions">True 'T',False 'F'</property>
<property name="query.substitutions">True='T',False='F'</property>
<property name="query.substitutions">True T,False F</property>

但这似乎不起作用。我找不到关于如何使用 query.substitutions 的一致文档,而且它似乎因您使用的数据库类型而异。

4

4 回答 4

2

您使用的是哪个版本的 NHibernate?

FieldValue 的属性类型是什么?

我将 NHibernate 与 Informix 一起使用,并且带有布尔限制的查询工作正常。这些是相关的配置值:

<property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
<property name="connection.driver_class">NHibernate.Driver.IfxDriver</property>
<property name="dialect">NHibernate.Dialect.InformixDialect1000</property>
于 2009-12-16T20:12:06.237 回答
1

对问题原始版本的评论

要回答这个问题,需要更多的信息——以及比评论更多的信息请求。

首先,我从讨论中假设您在某些 Windows 变体上使用 IBM Informix Dynamic Server (IDS)(但是是哪一个?)。请问你用的是哪个版本的IDS?另外,您使用的是哪个版本的 ClientSDK?

接下来,我假设您可以使用某个程序连接到 IDS 数据库 - 问题与通过 NHibernate 访问有关,而不是与访问有关。如果您的问题是您根本无法访问 IDS,那么调试步骤与“不通过替代访问方法”有很大不同。

当您通过其他方法连接时,(a)其他方法是什么,以及(b)您使用的连接字符串是什么?我想查看字符串值的“结构细节”。例如,如果您将数据库指定为“sensitive@secret”,我希望看到符号“xxxxxxxxx@yyyyyy”,因为虽然我们不一定需要知道这些名称是敏感的和秘密的,但我们确实需要大致知道名字的样子。对于字符串中的任何其他值也是如此。你说你删除了敏感信息,但你做的太彻底了,我不知道你提供的内容是否明智。

您是否使用过 SETNET32 设置任何 Informix 环境值——这个问题仅适用于 Windows 平台(Unix 使用常规环境变量而不是中央注册表)?如果是这样,你设置了什么?

非 NHibernate 包的工作连接字符串与 NHibernate 的非工作字符串相比如何?

最后(目前)您表明您曾尝试使用 IBM DB2 .NET 驱动程序和 Informix OLEDB 驱动程序。您需要注意,DB2 .NET 驱动程序使用 DRDA 协议与 IDS 通信,而 Informix 驱动程序使用 SQLI 协议。默认情况下,IDS 只侦听 SQLI 连接——您必须将 IDS 配置为接受 DRDA 连接。解决这个问题涉及到 IDS 管理的一些细节——我希望我们不需要处理,但我们可以。

如何将信息获取到 SO 上?我建议您编辑您的问题,将额外信息添加到问题中,以便其他人可以轻松查看问题。(我不是 Windows 上的 IDS 专家;我的后院是基于 Unix 的。我可能不得不让其他人协助提供答案,但还没有必要的信息。)

经修正的问题评论

IDS 以一种非正统的方式支持 BOOLEAN 类型——它不将truefalse(或unknown)识别为布尔值;它使用't'and'f'代替。因此,NHibernate 生成的代码对 IDS 无效(尽管我会接受它应该有效的参数)。我不清楚是否有解决问题的好方法。如果你能说服 NHibernate 传递引用的字符而不是 true 和 false,那么你就有了战斗的机会。

于 2009-12-02T01:56:51.330 回答
1

因此: fieldValue = 'T' 我得出的结论是 fieldValue 在数据库中具有 Char(1) 类型,而不是布尔值。如果是这样,您应该使用:

Restrictions.Eq("FieldValue", "T")

我没有对此进行测试,但我认为您的问题不是 Informix 特定的。对于不同的数据库,您将得到相同的错误。

这是因为每个 NHibernate 方言都提供了 ToBooleanValueString 方法。默认情况下,布尔值映射到“0”和“1”(因此在其他数据库中不能指望“T”),对于 Informix,它映射到“t”和“f”。显然 Restrictions.Eq 没有使用这种方法,这不是 Informix 错误。

可能 Restrictions.Eq 正在使用内部布尔变量(因为您的参数是布尔值)并调用其“ToString”方法,因为数据库列是字符类型。真值的“ToString”结果只是“真”。

于 2009-12-11T18:23:19.093 回答
0

出现问题是因为较新的 Informix 驱动程序使用不同的连接,并且误解了布尔值。

我找到的解决方案是创建一个新的 NHibernate 驱动程序,继承自 NHibernate.Driver.IfxDriver。在查询执行之前处理参数。

using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NHibernate;
using NHibernate.Driver;
using NHibernate.SqlCommand;
using NHibernate.SqlTypes;

namespace DataAccess
{
    public class NHibernateCustomDriver : NHibernate.Driver.IfxDriver
    {
        public override IDbCommand GenerateCommand(CommandType type, SqlString sqlString, SqlType[] parameterTypes)
        {
            IDbCommand cmd = CreateCommand();
            cmd.CommandType = type;

            SetCommandTimeout(cmd);
            SetCommandText(cmd, sqlString, parameterTypes);
            SetCommandParameters(cmd, parameterTypes);
            return cmd;
        }

        private void SetCommandText(IDbCommand cmd, SqlString sqlString, SqlType[] parameterTypes)
        {
            SqlStringFormatter formatter = GetSqlStringFormatter();
            formatter.Format(sqlString);

            int index = 0;
            int count = 0;
            string newCommand = formatter.GetFormattedText();
            index = newCommand.IndexOf("?");
            while (index >= 0)
            {
                if (parameterTypes[count].DbType == DbType.Boolean)
                {
                    newCommand = newCommand.Substring(0, index) + "CAST(?  AS BOOLEAN)" + newCommand.Substring(index + 1);
                    index = newCommand.IndexOf("?", index + 1);
                }
                count++;
                index = newCommand.IndexOf("?", index + 1);

            }

            cmd.CommandText = newCommand;

        }

        private void SetCommandParameters(IDbCommand cmd, SqlType[] sqlTypes)
        {
            for (int i = 0; i < sqlTypes.Length; i++)
            {
                string paramName = ToParameterName(i);
                IDbDataParameter dbParam = GenerateParameter(cmd, paramName, sqlTypes[i]);
                cmd.Parameters.Add(dbParam);
            }
        }

        private static string ToParameterName(int index)
        {
            return "p" + index;
        }
    }
}

NHibernate 配置必须设置为新类。

cfg.SetProperty("connection.driver_class", "DataAccess.NHibernateCustomDriver, DataAccess");

您还必须创建一个自定义类型来处理这些布尔值:

using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NHibernate.Type;

namespace DataAccess
{
    public class NHibernateUnixBooleanType : BooleanType
    {
        public override void Set(IDbCommand cmd, object value, int index)
        {
            cmd.Parameters[index] = CloneParameter(cmd, cmd.Parameters[index] as IDbDataParameter, value as bool?);
        }
        private IDbDataParameter CloneParameter(IDbCommand cmd, IDbDataParameter originalParameter, bool? value)
        {
            var clone = cmd.CreateParameter();
            clone.DbType = DbType.String;
            clone.Value = value.Value ? "t" : "f";
            clone.ParameterName = originalParameter.ParameterName;
            return clone;
        }
    }
}

并在映射文件上设置此类型:

<property name="Property" column="column" type="DataAccess.NHibernateUnixBooleanType, DataAccess"></property>
于 2015-09-11T19:04:57.437 回答