Informix 与 NHibernate

发布于 2024-08-13 03:31:42 字数 1249 浏览 3 评论 0原文

我正在尝试让 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 的形式。

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

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

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

select * from DBTable where fieldValue = 'T'

但它生成的 SQL 是,

select * from 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 的一致文档,并且它似乎根据您使用的数据库类型而有所不同。

I am trying to get Informix working with NHibernate on windows 7. I have a connection string that works fine with informix now, it is this,

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

I am using the IBM.Data.Informix .NET provider version 9.0.0.2.

We have a number of different applications that work fine using this provider with the Informix servers that we are running.

My nhibernate application is connecting to the informix server now, but the problem is the form of the SQL that it is producing.

If my nhibernate code looks like this,

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

I am new to Informix, but if I am not wrong the correct SQL would be this,

select * from DBTable where fieldValue = 'T'

But instead the SQL is it producing is,

select * from DBTable where fieldValue = True

Which is not working. I tried adding stuff like this to the nhibernate config file,

<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>

but that just doesn't seem to work. I couldn't find consistent documentation as to how to use the query.substitutions, and it seemed to differ depending on what database type you are using.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

生活了然无味 2024-08-20 03:31:42

您使用什么版本的 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>

What version of NHibernate are you using?

What is the property type of FieldValue?

I'm using NHibernate with Informix and queries with boolean restrictions work fine. These are the relevant configuration values:

<property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
<property name="connection.driver_class">NHibernate.Driver.IfxDriver</property>
<property name="dialect">NHibernate.Dialect.InformixDialect1000</property>
九命猫 2024-08-20 03:31:42

对问题原始版本的评论

要回答这个问题将需要更多的信息 - 以及比评论中容纳的更多的信息请求。

首先,我从讨论中假设您正在某种 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 传递引用的字符而不是 true 和 false,那么您就有机会了。

Commentary on original version of question

To answer this is going to require some more information - and more information requests than fits into a comment.

First, I assume from the discussion that you are using IBM Informix Dynamic Server (IDS) on some variant of Windows (but which one?). Which version of IDS are you using, please? Also, which version of the ClientSDK are you using?

Next, I assume that you can connect to the IDS database using some program - the problem is related to access via NHibernate, rather than access at all. If your problem is that you have not yet been able to access IDS at all, then the debugging steps are rather different from 'not via an alternative access method'.

When you connect via the other method, (a) what is that other method, and (b) what is the connection string you use? I would like to see the 'structural details' of string values. For example, if you specify the database as 'sensitive@secret', I'd like to see the notation 'xxxxxxxxx@yyyyyy' because although we don't necessarily need to know that the names are sensitive and secret, we do need to know roughly what the names look like. Similarly for any other value in the strings. You said you removed the sensitive information, but you've done it so thoroughly that I can't tell whether what you supplied was sensible.

Have you used SETNET32 to set any Informix environment values - a question that only applies to Windows platforms (Unix uses regular environment variables and not a central registry)? If so, what have you set?

How do the working connection strings for the non-NHibernate package compare with the non-working strings for NHibernate?

Lastly (for now) you showed that you had tried to use both the IBM DB2 .NET driver and the Informix OLEDB driver. You need to be aware that the DB2 .NET driver uses the DRDA protocol to talk to IDS, whereas the Informix driver uses the SQLI protocol. By default, IDS only listens for SQLI connections - you would have to configure IDS to accept the DRDA connections. Fixing that gets into some of the details of IDS administration - which I hope we don't need to deal with, but we may.

How to get the information onto SO? I suggest you edit your question, adding the extra information to the question so other people can easily see the issues. (I'm not an expert with IDS on Windows; my backyard is Unix-based. I will likely have to get other people to assist in providing the answer, but the necessary information isn't yet available.)

Commentary on question as amended

IDS supports BOOLEAN types in an unorthodox way - it does not recognize true or false (or unknown) as boolean values; it uses 't' and 'f' instead. Consequently, the code generated by NHibernate is not valid for IDS (though I'd accept arguments to the effect that it should be). I'm not clear whether there's a good way to resolve the problem. If you can persuade NHibernate to pass the quoted characters instead of true and false, then you're in with a fighting chance.

把昨日还给我 2024-08-20 03:31:42

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

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

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

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

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

Because of this:
fieldValue = 'T'
I'm drawing conclusion that fieldValue have Char(1) type in database, not boolean.
If so you should use:

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

I haven't tested this but I think that your issue is not Informix - specific. You'll get the same error with different database.

This is because every NHibernate dialect provides ToBooleanValueString method. By default boolean values are mapped to "0" and "1" (so you can't expect "T" in other databases) and for Informix it is mapped to "t" and "f". Apparently this method is not used by Restrictions.Eq which is not Informix fault.

Probably Restrictions.Eq is using internally boolean variable (because your argument is boolean) and calls its "ToString" method because database column is of character type.
Result of "ToString" for true value is just "true".

迷离° 2024-08-20 03:31:42

发生问题的原因是较新的 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>

The problem is happening because the newer Informix drivers are using the different connections, and it is misunderstanding the booleans.

The solution that I found is to create a new NHibernate Driver, inherited from NHibernate.Driver.IfxDriver. Treating the parameters just before the query execution.

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;
        }
    }
}

The NHibernate configuration must be set to the new class.

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

You also have to create a custom type, to handle those booleans:

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;
        }
    }
}

And set this type on the mapping file:

<property name="Property" column="column" type="DataAccess.NHibernateUnixBooleanType, DataAccess"></property>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文