NHibernate: объединить коллекцию на других, кроме составных ключей, указанных в сопоставлении - PullRequest
4 голосов
/ 01 февраля 2012

В устаревшей базе данных мне приходится работать с вложенными таблицами, которые связаны через составные ключи. В переводе на NHibernate я, например, класс FcoTransproduction, который имеет коллекцию детей класса FcoConsignment. Однако в одной ситуации я хотел бы загрузить коллекцию на основе только одного из компонентов составного ключа и игнорировать другой компонент.

Отображение выглядит так:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" default-lazy="false">
  <class name="FcoLib.FcoTransportation, FcoLib" table="FCO_TRANSPORTATION">
    <composite-id>
    <key-property name="ID"/>
  <key-property name="FK_EventID"/>
</composite-id>
<!--...snip...-->
<bag name="Consignments" table="FCO_Consignment" lazy="false" cascade="save-update">
  <key>
    <column name="FK_TransportationID"/>
    <column name="FK_EventID"/>
  </key> 
  <one-to-many class="FcoLib.FcoConsignment, FcoLib"/>
</bag>
<!--...snip...-->

Я пытался создать этот запрос, используя обычные критерии NHibernate, SQL и HQL. Вот что я получил в HQL, что по крайней мере загружает транспорты без ошибок:

 String queryString = "select ft from FcoTransportation as ft";
 queryString += " join ft.Consignments as fc on fc.FK_TransportationID = :ID";

 var query = session.CreateQuery(queryString);

 transports = query
                .SetMaxResults(100)
                .List<FcoTransportation>();  

Тем не менее, сбор грузов остается пустым! Как мне это решить!?

В качестве дополнения я хотел бы отсеять любые дублирующиеся дочерние элементы, выбрав те записи с наивысшими значениями в двух столбцах «ChangedDate» и «ChangedTime» соответственно.


В качестве последнего средства я рассматриваю возможность полного удаления составного сопоставления клавиш. В этом случае мне все равно придется удалять дубликаты на основе последней версии ChangedDate / ChangedTime ...


ОБНОВЛЕНИЕ : Я попытался удалить сопоставления составного ключа, но затем я получаю ошибку, которая, по-видимому, выдается, потому что составные внешние ключи применяются, даже когда я пытаюсь их игнорировать. Так что за хитрость в том, чтобы убедить NHibernate НЕ применять это, поскольку я легко могу написать SQL-запрос в SQL Srv Mgt Studio, выполнив следующее:

SELECT TOP 100 *
  FROM [FCO_EVENT] AS e 
  INNER JOIN [FCO_TRANSPORTATION] AS t ON e.FK_TransportationID = t.ID
  --children:
  LEFT OUTER  JOIN [FCO_CONSIGNMENT] AS c ON c.FK_TransportationID = t.ID 
  LEFT OUTER JOIN [FCO_CONSIGNMENT_LINES] AS cl ON cl.FK_ConsignmentID = c.ID 

ОБНОВЛЕНИЕ : Было предложено использовать выборку соединения, которая выглядит многообещающе, но по-прежнему не выбираются дети:

 String queryString = "select ft from FcoTransportation as ft where ft.ID ='" + guid + "'";
 queryString += " join fetch ft.Consignments as fc on fc.FK_TransportationID = '" + guid + "'";

ОБНОВЛЕНИЕ : Было также предложено сделать так называемое объединение в "тэта-стиле", которое выглядит ниже, но и здесь коллекция потомков не заполняется:

String queryString  = "select ft from FcoTransportation as ft, FcoConsignment as fc"
                    + " where ft.ID = fc.FK_TransportationID"
                    + " and ft.ID = '" + guid + "'";

ПРИМЕЧАНИЕ : Мне нужно только получить данные, а не сохранить их снова. У меня уже есть запрос на получение грузов для каждого транспорта (в большинстве случаев их десятки, но обычно несколько, а в отдельных случаях - несколько сотен). Я просто хочу быть экономичным с количеством обращений к базе данных. Вот почему я хотел бы, чтобы груз доставлялся одновременно с доставкой транспорта.

Ответы [ 3 ]

1 голос
/ 12 февраля 2012

Я думаю, вы неправильно подходите к этому.Отображение отношения один-ко-многим является объектно-ориентированным эквивалентом отношения внешнего ключа в реляционной базе данных.Возможность фильтровать или получать другое представление о дочерней коллекции не имеет смысла в этом контексте.Предполагая, что вы можете сделать это, как NHibernate может сохранить изменения в отфильтрованной дочерней коллекции?Если NHibernate не может его сохранить, то он смоделирован неправильно.Ваше желание также «отсеять дублирующихся дочерних элементов, отдав предпочтение тем записям с наивысшими значениями в двух столбцах« ChangedDate »и« ChangedTime »», подкрепляет этот вывод.

Я бы просто создал запрос для возврата отправленных вами грузовхочу.Используя Future, вы можете заключить его в метод, который будет возвращать объект FcoTransproduction, и запрос приведет к единственному обращению к базе данных.

Другой вариант - добавить метод в FcoTransproduction, который фильтрует дочернюю коллекцию.Если количество отправлений является разумным (<10000?) И вам часто требуется фильтровать сбор таким образом, я бы выбрал этот вариант. </p>

0 голосов
/ 10 февраля 2012

Попробуйте это

select ft from FcoTransportation as ft, FcoConsignment as fc
where ft.Id = fc.Transportation.Id

Я не знаю название свойства навигации от FcoConsignment до FcoTransproduction, поэтому я назвал его Транспорт.

0 голосов
/ 09 февраля 2012

В настоящее время вы просто присоединяетесь, не выбирая дочерние элементы, поэтому попробуйте использовать «выборку объединения» вместо простого объединения:

select ft from FcoTransportation as ft join fetch ft.Consignments as fc on fc.FK_TransportationID = :ID

Это должно помочь.

...