Предупреждение - я очень новичок в NHibernate. Я знаю, что этот вопрос кажется простым - и я уверен, что на него есть простой ответ, но я уже некоторое время ломаю голову над этим вопросом. Я имею дело с унаследованной базой данных, которая действительно не может быть изменена структурно. У меня есть таблица деталей, в которой перечислены планы платежей, которые были приняты клиентом. Каждый план платежей имеет идентификатор, который ссылается на справочную таблицу, чтобы получить условия, положения и т.д. В моей объектной модели у меня есть класс AcceptedPlan и класс Plan. Изначально я использовал связь "многие-к-одному" от подробной таблицы обратно к таблице ref для моделирования этой связи в NHibernate. Я также создал отношение "один-ко-многим", идущее в обратном направлении от класса Plan к классу AcceptedPlan. Это было прекрасно, пока я просто читал данные. Я мог обратиться к своему объекту Plan, который был свойством класса AcceptedPlan, чтобы прочитать детали плана. Проблема возникла, когда мне нужно было начать вставлять новые строки в таблицу деталей. Судя по прочитанному, единственный способ создать новый дочерний объект - это добавить его к родительскому объекту, а затем сохранить сессию. Но я не хочу создавать новый родительский объект Plan каждый раз, когда я хочу создать новую подробную запись. Это кажется ненужным накладным расходом. Кто-нибудь знает, может быть, я делаю это неправильно?
I' d держатся далеко от наличия дочернего объекта, содержащего их логического родителя, это может стать очень грязным и очень рекурсивным довольно быстро, когда Вы делаете это. I' d смотрят на как you' ре, намеревающееся использовать модель области, прежде чем Вы сделаете такую вещь. Вы можете легко тихий иметь идентификационные ссылки в столах и просто оставлять их ненанесенными на карту.
Вот два отображения в качестве примера, которые могли бы подтолкнуть Вас в правильном направлении, I' ve должен был выдать экспромтом имена таблиц и т.д., но он мог возможно помочь. I' d, вероятно, также предлагают нанести на карту StatusId к перечислению.
Обратите внимание на способ, которым сумка effectivly наносит на карту стол деталей в коллекцию.
<?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>
Didn' t видят Вашу диаграмму базы данных, пока я писал.
<?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>
Должен, вероятно, добиться цели (I' ve только сделанные отображения в качестве примера для коллекций, you' ll должны добавить другие свойства).
Я бы использовал следующий подход к моделированию:
Объект Customer содержит ICollection
PaymentPlan к клиенту будет сопоставлен с помощью пакета, который использует таблицу деталей, чтобы определить, какие идентификаторы клиентов сопоставлены с какими PaymentPlans. При использовании каскадного метода all-delete-orphan, если клиент будет удален, то будут удалены и записи из таблицы details, и принадлежащие клиенту планы платежей.
Объект PaymentPlan содержит объект PlanTerms, который представляет условия плана платежей.
PlanTerms будет сопоставлен с PaymentPlan с помощью каскадного каскадного сохранения-апдейта, который просто вставит ссылку на соответствующий объект PlanTerms в PaymentPlan.
Используя эту модель, вы можете создавать PlanTerms независимо друг от друга, а затем, когда вы добавляете новый PaymentPlan к клиенту, вы создаете новый объект PaymentPlan, передавая в него соответствующий объект PlanTerms, а затем добавляете его в коллекцию соответствующего клиента. Наконец, вы сохраните клиента и позволите nhibernate каскадировать операцию сохранения.
В итоге вы получите объект Customer, объект PaymentPlan и объект PlanTerms, где Customer (таблица customer) владеет экземплярами PaymentPlans (таблица details), которые соответствуют определенным PlanTerms (таблица plan).
У меня есть несколько более конкретных примеров синтаксиса отображения, если это необходимо, но, вероятно, лучше всего проработать это с вашей собственной моделью, и у меня нет достаточной информации о таблицах базы данных, чтобы предоставить какие-либо конкретные примеры.
Я не знаю, возможно, это из-за моего ограниченного опыта работы с NHibernate, но не могли бы вы создать класс BaseDetail, который имеет только свойства для Details, поскольку они отображаются непосредственно на таблицу Detail.
Затем создайте второй класс, который наследуется от класса BaseDetail и имеет дополнительный объект Parent Plan, таким образом, вы можете создать класс BaseDetail, когда вы хотите просто создать строку Detail и присвоить ей PlanId, но если вам нужно заполнить полную запись Detail объектом Parent plan, вы можете использовать наследуемый класс Detail.
Я не знаю, имеет ли это большой смысл, но дайте мне знать, и я проясню ситуацию.
Я думаю, что проблема у вас в том, что ваш объект AcceptedOffer содержит объект Plan, а затем ваш объект Plan, похоже, содержит коллекцию AcceptedOffers, которая содержит объекты AcceptedOffer. То же самое с Customers. Тот факт, что объекты являются дочерними по отношению друг к другу, является причиной вашей проблемы, я думаю.
Аналогично, что делает ваш AcceptedOffer сложным, так это то, что у него две ответственности: он указывает на предложения, включенные в план, и указывает на принятие их клиентом. Это нарушает принцип единой ответственности.
Возможно, вам придется различать предложения, включенные в план, и предложения, принятые клиентами. Вот что я собираюсь сделать:
Я думаю, это в достаточной степени распутает ваши проблемы с отображениями NHibernate и сохранением объектов :)
Наконечник, который может (или не может) быть полезным в NHibernate: Вы можете нанести на карту свои объекты против Взглядов, как будто Представление было столом. Просто определите имя представления как имя таблицы; пока все НЕ ПУСТЫЕ области включены в представление, и отображение его будет хорошо работать.