使用NHibernate的Informix

时间:2009-12-02 00:48:43

标签: nhibernate informix

我试图让Informix在Windows 7上使用NHibernate。我有一个连接字符串,现在可以正常使用informix,就是这样,

数据库=分贝;服务器=服务器:端口; UID =用户名,密码=密码;池=假

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

我们有许多不同的应用程序可以使用此提供程序与我们正在运行的Informix服务器一起正常工作。

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

如果我的nhibernate代码看起来像这样,

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

我是Informix的新手,但如果我没有错,那么正确的SQL就是这个,

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

但是,它生成的是SQL,

从DBTable中选择*,其中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 个答案:

答案 0 :(得分: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>

答案 1 :(得分: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''f'代替。因此,NHibernate生成的代码对IDS无效(尽管我接受它应该有效的参数)。我不清楚是否有一个解决问题的好方法。如果你能说服NHibernate传递被引用的字符而不是真和假,那么你就有了战斗机会。

答案 2 :(得分:1)

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

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

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

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

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

答案 3 :(得分:0)

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

我找到的解决方案是创建一个新的NHibernate Driver,继承自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>