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

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

14.08.2008 11:56:29
6 ОТВЕТОВ
РЕШЕНИЕ

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

Вот два примера сопоставления, которые могут подтолкнуть вас в правильном направлении, мне пришлось добавить имена таблиц и т. Д., Но это могло бы помочь. Я бы, вероятно, также предложил сопоставить 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>
3
14.08.2008 15:04:15

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

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

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

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

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

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

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

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

0
14.08.2008 13:23:43

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

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

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

0
14.08.2008 13:25:49

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

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

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

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

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

0
14.08.2008 15:00:42

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

0
11.08.2012 15:51:17

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

<?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>

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

1
14.08.2008 15:12:04