我试图让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的一致文档,它似乎根据您使用的数据库类型而有所不同。
答案 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类型 - 它不会将true
或false
(或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>