Informix с NHibernate - PullRequest
       40

Informix с NHibernate

1 голос
/ 02 декабря 2009

Я пытаюсь заставить Informix работать с NHibernate на Windows 7. У меня есть строка подключения, которая теперь отлично работает с informix, вот она,

База данных = дб; Server = сервер: порт; 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.substitutiontions, и она, казалось, отличалась в зависимости от того, какой тип базы данных вы используете.

Ответы [ 4 ]

2 голосов
/ 16 декабря 2009

Какую версию 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 голос
/ 11 декабря 2009

Из-за этого: 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" для истинного значения просто "true".

1 голос
/ 02 декабря 2009

Комментарий к оригинальной версии вопроса

Чтобы ответить на этот вопрос, потребуется больше информации - и больше информационных запросов, чем помещается в комментарии.

Во-первых, из обсуждения я предполагаю, что вы используете IBM Informix Dynamic Server (IDS) в каком-то варианте Windows (но какой?). Какую версию IDS вы используете, пожалуйста? Кроме того, какую версию ClientSDK вы используете?

Далее, я предполагаю, что вы можете подключиться к базе данных IDS с помощью некоторой программы - проблема связана с доступом через NHibernate, а не с доступом вообще. Если ваша проблема заключается в том, что вы еще не смогли получить доступ к IDS, то этапы отладки несколько отличаются от «не с помощью альтернативного метода доступа».

Когда вы подключаетесь через другой метод, (a) что это за другой метод и (b) какую строку подключения вы используете? Я хотел бы видеть «структурные детали» строковых значений. Например, если вы укажете базу данных как «чувствительный @ секретный», я хотел бы видеть нотацию «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? Я предлагаю вам отредактировать свой вопрос, добавив к нему дополнительную информацию, чтобы другие люди могли легко увидеть проблемы. (Я не специалист по IDS в Windows; мой задний двор основан на Unix. Мне, вероятно, придется привлекать других людей для предоставления ответа, но необходимой информации пока нет.)

Комментарий к вопросу с поправками

IDS поддерживает BOOLEAN типы неортодоксальным способом - он не распознает true или false (или unknown) как логические значения; вместо этого он использует 't' и 'f'. Следовательно, код, сгенерированный NHibernate, недопустим для IDS (хотя я бы принял аргументы о том, что так и должно быть). Мне не ясно, есть ли хороший способ решить проблему. Если вы сможете убедить NHibernate пропустить символы, указанные в кавычках, вместо true и false, тогда у вас есть шанс на победу.

0 голосов
/ 11 сентября 2015

Проблема возникает из-за того, что более новые драйверы 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>
...