NH4 LINQ Запрос с использованием неправильного столбца для одного к одному
У меня есть отношение один к одному между двумя таблицами, и я хочу иметь возможность создать запрос LINQ, который будет возвращать "родительские" таблицы, где есть что-то в дочерней таблице. Проблема заключается в том, что запрос NH, который генерирует, проверяет, не является ли идентификатор родительской таблицы нулевым (и никогда не является), а не присоединяется к дочерней таблице. Это независимо от того, использую я ленивую или не ленивую загрузку. Я использую пользовательские соглашения об автоматах с переопределением, но вот генерируемый XML HBM:
Отображение для абстрактного класса, конкретного класса, который является родительским
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<class xmlns="urn:nhibernate-mapping-2.2" name="AbstractClass, DomainObjects, Version=2.2.1.0, Culture=neutral, PublicKeyToken=aaaaaaaaaaaaaaaa" table="ABSTRACT_CLASS">
<id name="AbstractClassId" type="System.Nullable`1[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name="ABSTRACT_CLASS_ID" />
<generator class="identity" />
</id>
<joined-subclass name="ConcreteClass, DomainObjects, Version=2.2.1.0, Culture=neutral, PublicKeyToken=aaaaaaaaaaaaaaaa" table="CONCRETE_CLASS">
<key>
<column name="ABSTRACT_CLASS_ID" />
</key>
<one-to-one cascade="none" class="AuxiliaryClass, DomainObjects, Version=2.2.1.0, Culture=neutral, PublicKeyToken=aaaaaaaaaaaaaaaa" name="AuxiliaryClass" property-ref="Foo" />
</joined-subclass>
</class>
</hibernate-mapping>
Картографирование для дочернего стола
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<class xmlns="urn:nhibernate-mapping-2.2" name="AuxiliaryClass, DomainObjects, Version=2.2.1.0, Culture=neutral, PublicKeyToken=aaaaaaaaaaaaaaaa" table="AUXILIARY_CLASS">
<id name="AuxiliaryClassiD" type="System.Nullable`1[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<column name="AUXILIARY_CLASS_ID" />
<generator class="identity" />
</id>
<many-to-one class="ConcreteClass, DomainObjects, Version=2.2.1.0, Culture=neutral, PublicKeyToken=aaaaaaaaaaaaaaaa" name="Foo">
<column name="FOO_ABSTRACT_CLASS_ID" />
</many-to-one>
</class>
</hibernate-mapping>
Определения классов
public abstract class AbstractClass
{
public virtual Int32? AbstractClassId { get; set; }
}
public class ConcreteClass : AbstractClass
{
public virtual AuxiliaryClass AuxiliaryClass { get; set; }
}
public class AuxiliaryClass
{
public virtual Int32? AuxiliaryClassId { get; set; }
public virtual ConcreteClass Foo { get; set; }
}
Неработающий запрос LINQ:
nh.Query<ConcreteClass>().Where(cc => cc.AuxiliaryClass != null);
Сгенерированный запрос:
select
concretecl0_.CONCRETE_CLASS_ID as CONCRETE1_0_
from
CONCRETE_CLASS concretecl0_
inner join
ABSTRACT_CLASS concretecl0_1_
on
concretecl0_.ABSTRACT_CLASS_ID=concretecl0_1_.ABSTRACT_CLASS_ID
where
concretecl0_.ABSTRACT_CLASS_ID is not null
Если я отключаю отложенную загрузку, соединения присоединяются к вспомогательной таблице, но все равно сравнивают идентификатор таблицы конкретного класса с нулем.
редактировать
Предложение Per @Suhas:
Попробуйте изменить свой запрос Linq на nh.Query(cc => cc.AuxiliClass.AuxiliClassId > 0); при условии, что AuxiliaryClassId имеет тип int
Я действительно сделал cc => cc.AuxiliaryClass.AuxiliaryClassId != null
, который работал, получая мне этот запрос:
select
concretecl0_.ABSTRACT_CLASS_ID as concretecl0_1_0_
from
CONCRETE_CLASS concretecl0_
inner join
ABSTRACT_CLASS concretecl0_1_
on
concretecl0_.concretecl0_=concretecl0_1_.concretecl0_
, AUXILIARY_CLASS auxiliaryc1_
where
concretecl0_.ABSTRACT_CLASS_ID=auxiliaryc1_.FOO_ABSTRACT_CLASS_ID
and (auxiliaryc1_.AUXILIARY_CLASS_ID is not null)
Тем не менее, когда я попробовал обратный случай, cc => cc.AuxiliaryClass.AuxiliaryClassId == null
Я получил нерабочий запрос:
select
concretecl0_.ABSTRACT_CLASS_ID as concretecl0_1_0_
from
CONCRETE_CLASS concretecl0_
inner join
ABSTRACT_CLASS concretecl0_1_
on
concretecl0_.concretecl0_=concretecl0_1_.concretecl0_
, AUXILIARY_CLASS auxiliaryc1_
where
concretecl0_.ABSTRACT_CLASS_ID=auxiliaryc1_.FOO_ABSTRACT_CLASS_ID
and (auxiliaryc1_.AUXILIARY_CLASS_ID is null)
1 ответ
Просто перечислил мои комментарии (слегка адаптированные к ответу) из исходных вопросов, поскольку те, кажется, помогли автору вопроса
- Попробуйте изменить свой запрос Linq на
nh.Query<ConcreteClass>(cc => cc.AuxiliaryClass.AuxiliaryClassId > 0);
при условии,AuxiliaryClassId
имеет типint
- Выше не будет работать, если вы хотите получить записи, присутствующие в
ConcreteClass
но не присутствует вAuxiliaryClass
, Для этого вы можете использовать левое внешнее соединение. Если вы выполняете левое внешнее соединение, то вы можете сделать это через QueryOver (или Linq не таким прямым способом), а затем выполнить проверку на нуль в вашем коде. В зависимости от размера набора данных, который вы загружаете, это может быть нехорошо в производственной среде. Я не уверен, как бы сделать подзапрос, чтобы достичь того, что вы пытаетесь достичь - если LINQ является единственным вариантом, то вы можете использовать
DefaultIfEmpty
метод для получения левого внешнего соединения в LINQ. Этот ТАК вопрос должен быть хорошей отправной точкой. - Наконец, простой SQL может быть наиболее эффективным в этой ситуации. Если вы хотите пойти по этому маршруту, то вы можете использовать
ISession.CreateSQLQuery
и использовать ваш SQL-запрос как есть