Лучший способ моделирования отношений «многие к одному» в NHibernate при работе с устаревшей БД? - PullRequest
3 голосов
/ 14 августа 2008

Предупреждение - я очень новичок в NHibernate. Я знаю, что этот вопрос кажется простым - и я уверен, что есть простой ответ, но я уже некоторое время крутил свои колеса на этом. Я имею дело с устаревшей БД, которая действительно не может быть структурно изменена. У меня есть таблица данных, в которой перечислены планы платежей, которые были приняты клиентом. У каждого плана платежей есть идентификатор, который ссылается на справочную таблицу для получения условий, условий и т. Д. В моей объектной модели у меня есть класс AcceptedPlan и класс Plan. Первоначально я использовал отношение многие-к-одному от таблицы сведений до таблицы ссылок, чтобы смоделировать это отношение в NHibernate. Я также создал отношение «один ко многим», идущее в противоположном направлении от класса Plan к классу AcceptedPlan. Это было хорошо, пока я просто читал данные. Я мог перейти к своему объекту Plan, который был свойством моего класса AcceptedPlan, чтобы прочитать детали плана. Моя проблема возникла, когда мне пришлось начать вставлять новые строки в таблицу сведений. Из моего прочтения кажется, что единственный способ создать новый дочерний объект - это добавить его в родительский объект и затем сохранить сеанс. Но я не хочу создавать новый родительский объект Plan каждый раз, когда я хочу создать новую подробную запись. Это кажется ненужными накладными расходами. Кто-нибудь знает, неправильно ли я поступаю?

Ответы [ 6 ]

3 голосов
/ 14 августа 2008

Я бы держался подальше от того, чтобы дочерний объект содержал их логического родителя, он может стать очень грязным и очень рекурсивным довольно быстро, когда вы сделаете это. Я бы посмотрел, как вы собираетесь использовать модель предметной области, прежде чем делать подобные вещи. Вы по-прежнему можете легко хранить ссылки на идентификаторы в таблицах и просто оставить их без отображения.

Вот два примера сопоставлений, которые могут подтолкнуть вас в правильном направлении, мне пришлось добавить имена таблиц и т. Д., Но это могло бы помочь. Возможно, я бы также предложил сопоставить StatusId с перечислением.

Обратите внимание на то, как сумка эффективно отображает таблицу данных в коллекцию.

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping default-cascade="save-update" xmlns="urn:nhibernate-mapping-2.2">
    <class lazy="false" name="Namespace.Customer, Namespace" table="Customer">
        <id name="Id" type="Int32" unsaved-value="0">
            <column name="CustomerAccountId" length="4" sql-type="int" not-null="true" unique="true" index="CustomerPK"/>
            <generator class="native" />
        </id>

        <bag name="AcceptedOffers" inverse="false" lazy="false" cascade="all-delete-orphan" table="details">
          <key column="CustomerAccountId" foreign-key="AcceptedOfferFK"/>
          <many-to-many
            class="Namespace.AcceptedOffer, Namespace"
            column="AcceptedOfferFK"
            foreign-key="AcceptedOfferID"
            lazy="false"
           />
        </bag>

  </class>
</hibernate-mapping>


<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping default-cascade="save-update" xmlns="urn:nhibernate-mapping-2.2">
    <class lazy="false" name="Namespace.AcceptedOffer, Namespace" table="AcceptedOffer">
        <id name="Id" type="Int32" unsaved-value="0">
            <column name="AcceptedOfferId" length="4" sql-type="int" not-null="true" unique="true" index="AcceptedOfferPK"/>
            <generator class="native" />
        </id>

        <many-to-one 
          name="Plan"
          class="Namespace.Plan, Namespace"
          lazy="false"
          cascade="save-update"
        >
        <column name="PlanFK" length="4" sql-type="int" not-null="false"/>
        </many-to-one>

        <property name="StatusId" type="Int32">
            <column name="StatusId" length="4" sql-type="int" not-null="true"/>
        </property>

  </class>
</hibernate-mapping>
1 голос
/ 14 августа 2008

Не видел диаграмму вашей базы данных, пока я писал.

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping default-cascade="save-update" xmlns="urn:nhibernate-mapping-2.2">
    <class lazy="false" name="Namespace.Customer, Namespace" table="Customer">
        <id name="Id" type="Int32" unsaved-value="0">
            <column name="customer_id" length="4" sql-type="int" not-null="true" unique="true" index="CustomerPK"/>
            <generator class="native" />
        </id>

        <bag name="AcceptedOffers" inverse="false" lazy="false" cascade="all-delete-orphan">
            <key column="accepted_offer_id"/>
            <one-to-many class="Namespace.AcceptedOffer, Namespace"/>
        </bag>

  </class>
</hibernate-mapping>


<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping default-cascade="save-update" xmlns="urn:nhibernate-mapping-2.2">
    <class lazy="false" name="Namespace.AcceptedOffer, Namespace" table="Accepted_Offer">
        <id name="Id" type="Int32" unsaved-value="0">
            <column name="accepted_offer_id" length="4" sql-type="int" not-null="true" unique="true" />
            <generator class="native" />
        </id>

        <many-to-one name="Plan" class="Namespace.Plan, Namespace" lazy="false" cascade="save-update">
            <column name="plan_id" length="4" sql-type="int" not-null="false"/>
        </many-to-one>

  </class>
</hibernate-mapping>

Скорее всего, стоит добиться цели (я только сделал примеры сопоставлений для коллекций, вам нужно будет добавить другие свойства).

0 голосов
/ 14 августа 2008

Совет, который может (или не может) быть полезен в NHibernate: вы можете сопоставить свои объекты с представлениями, как если бы представление было таблицей. Просто укажите имя представления в качестве имени таблицы; до тех пор, пока все поля NOT NULL включены в представление и отображение будет работать нормально.

0 голосов
/ 14 августа 2008

Я думаю, что проблема здесь в том, что ваш объект AcceptedOffer содержит объект Plan, а затем ваш объект Plan содержит коллекцию AcceptedOffers, которая содержит объекты AcceptedOffer. То же самое с клиентами. Я думаю, что тот факт, что объекты являются дочерними по отношению друг к другу, является причиной вашей проблемы.

Аналогично, то, что делает ваш AcceptedOffer сложным, состоит в том, что он имеет две обязанности: он указывает на предложения, включенные в план, он указывает на принятие клиентом. Это нарушает принцип единой ответственности.

Возможно, вам придется различать Предложение, находящееся в рамках Плана, и Предложение, принятое клиентами. Вот что я собираюсь сделать:

  1. Создайте отдельный объект предложения, у которого нет состояния, например, у него нет покупателя и у него нет статуса - у него есть только идентификатор предложения и план, которому он принадлежит, в качестве его атрибутов.
  2. Измените свой объект плана, чтобы иметь коллекцию предложений (он не должен был принимать предложение в своем контексте).
  3. Наконец, измените ваш объект AcceptedOffer, чтобы он содержал Предложение, Клиента и Статус. Клиент остается прежним.

Я думаю, что это достаточно распутает ваши отображения NHibernate и проблемы сохранения объектов. :)

0 голосов
/ 14 августа 2008

Я не знаю, возможно ли это потому, что мой опыт работы с NHibernate ограничен, но не могли бы вы создать класс BaseDetail, который имеет только свойства для деталей, поскольку они отображаются непосредственно в таблицу деталей.

Затем создайте второй класс, который наследуется от класса BaseDetail, у которого есть дополнительный объект Parent Plan, чтобы вы могли создать класс BaseDetail, когда вы хотите просто создать строку Detail и присвоить ей PlanId, но если вам нужно заполнить полная запись сведений с объектом родительского плана, которую вы можете использовать унаследованным классом сведений.

Я не знаю, имеет ли это большой смысл, но дайте мне знать, и я уточню дальше.

0 голосов
/ 14 августа 2008

Подход, который я бы выбрал для моделирования, заключается в следующем:

Объект Customer содержит ICollection PaymentPlans, который представляет планы, принятые клиентом.

PaymentPlan для Клиента будет отображаться с помощью пакета, который использует таблицу данных, чтобы определить, какой идентификатор клиента сопоставлен с каким PaymentPlans. При использовании cascade all-delete-orphan, если клиент был удален, будут удалены как записи из деталей, так и PaymentPlans, которыми владеет клиент.

Объект PaymentPlan содержит объект PlanTerms, который представляет условия плана платежей.

PlanTerms будет сопоставлен с PaymentPlan с использованием каскадного сохранения обновления много-к-одному, которое просто вставит ссылку на соответствующий объект PlanTerms в PaymentPlan.

Используя эту модель, вы можете создавать PlanTerms независимо, а затем, когда вы добавляете новый PaymentPlan к клиенту, вы создаете новый объект PaymentPlan, передающий соответствующий объект PlanTerms, а затем добавляете его в коллекцию соответствующего клиента. Наконец, вы должны сохранить клиента и позволить nhibernate каскадировать операцию сохранения.

В конечном итоге вы получите объект Customer, объект PaymentPlan и объект PlanTerms с клиентом (таблица клиента), которому принадлежат экземпляры PaymentPlans (таблица подробностей), которые все привязаны к определенным PlanTerms (таблица плана).

У меня есть несколько более конкретных примеров синтаксиса отображения, если это необходимо, но, вероятно, лучше проработать его с вашей собственной моделью, и у меня недостаточно информации о таблицах базы данных, чтобы привести какие-либо конкретные примеры.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...