nHibernate терпит неудачу с ограничением whereNot, но не с ограничением where - PullRequest
0 голосов
/ 21 апреля 2020

В настоящее время я работаю над проектом C#, в котором мы используем NHibernate. В проекте у нас есть таблица «Auftrag», где мне нужны только некоторые столбцы.

Чтобы выбрать только нужные мне столбцы, я использую этот код:

ProjectionList projectionListSubTypeAuftrag = Projections.ProjectionList();
projectionListSubTypeAuftrag
    .Add(Projections.Property("AuftragID"), "Id")
    .Add(Projections.Property("Status"), "Status")
    .Add(Projections.Property("Typ"), "Typ");

DetachedCriteria auftragCriteria = DetachedCriteria.For(typeof(Auftrag));

auftragCriteria.SetProjection(projectionListSubTypeAuftrag);
auftragCriteria.SetResultTransformer(Transformers.AliasToBean(typeof(SubTypeAuftrag)));

IList<SubTypeAuftrag> auftragSubview;

using (ITransaction tx = session.BeginTransaction())
{
    auftragSubview = auftragCriteria.GetExecutableCriteria(session).List<SubTypeAuftrag>();

    tx.Commit();
}

Это работает нормально и возвращает все строки в таблице. Теперь я хочу выполнить фильтрацию с условием: Status != 'A'.

Я попытался добиться этого с помощью следующей строки

auftragCriteria.Add(Restrictions.Not(Restrictions.Eq("Status", 'A')));

Если я сейчас запускаю код, я получаю исключение:

System.Data.SqlClient.SqlException: создание или изменение таблицы 'FakeWorkTable' не выполнено, поскольку минимальный размер строки будет 16017, включая 4 байта внутренних издержек. Это превышает максимально допустимый размер строки таблицы в 8094 байта.

Когда я смотрю на сгенерированный оператор SQL, все выглядит нормально, я также могу запустить его в Microsoft SSMS.

Теперь часть, которую я не понимаю, когда я изменяю auftragCriteria.Add(Restrictions.Not(Restrictions.Eq("Status", 'A'))); на auftragCriteria.Add(Restrictions.Eq("Status", 'A'));, все работает нормально.

Чего мне не хватает?

Я нашел работу вокруг:

auftragCriteria.Add(Expression.Sql("Status <> 'A'"));

работает.

Если я использую auftragCriteria.Add(Restrictions.Not(Restrictions.Eq("Status", 'A')));, я получаю sql запрос

SELECT this_.auftragid as y0_,
       this_.status    as y1_,
       this_.typ       as y2_
FROM   auftrag this_
WHERE  not (this_.status = 'A' /* @p0 */)

И если я использую auftragCriteria.Add(Expression.Sql("Status <> 'A'"));, я получаю это:

SELECT this_.auftragid as y0_,
       this_.status    as y1_,
       this_.typ       as y2_
FROM   auftrag this_
WHERE  Status <> 'A'

Разве они не должны вести себя одинаково?

1 Ответ

0 голосов
/ 21 апреля 2020

Насколько я могу судить по исходному коду NHibernate, использование Restrictions.Not(Restrictions.Eq("Status", 'A')) кажется правильным способом реализации оператора "не равно". В Java версии Hibernate есть Restrictions.ne, который преобразуется в оператор «<>».

Мало что я бы проверил. Запустите ваш код с последней версией NHibernate и посмотрите, сохраняется ли проблема. Судя по сообщению об ошибке, я подозреваю, что в вашем коде происходит больше событий, которые вы здесь показали. Попробуйте воспроизвести проблему с наименьшим количеством кода, который вы только можете.

Другой обходной путь, который, я бы сказал, лучше, чем использование Expression.Sql, - это использование Lt и Gt с Or:

auftragCriteria.Add(
    Restrictions.Or(
        Restrictions.Lt("Status", 'A'), 
        Restrictions.Gt("Status", 'A')));

Что должно стать:

WHERE (this_.status < 'A' or this.status > 'A')

PS: я написал небольшой пример с использованием NHibernate 5.1.6 и Restrictions.Not работает, как и следовало ожидать. Я не верю, что ваша проблема связана с версией NHibernate.

...