警告 - 我对NHibernate很新。我知道这个问题看起来很简单 - 而且我确信这是一个简单的答案,但我已经在这个问题上旋转了一段时间。我正在处理一个真正无法在结构上进行修改的遗留数据库。我有一个详细信息表,其中列出了客户已接受的付款计划。每个付款计划都有一个ID,该ID链接回参考表以获取计划的条款,条件等。在我的对象模型中,我有一个AcceptedPlan类和一个Plan类。最初,我使用了从详细信息表到ref表的多对一关系来在NHibernate中建模这种关系。我还创建了一个从Plan类到AcceptedPlan类的相反方向的一对多关系。我只是在阅读数据时很好。我可以去我的Plan对象,这是我的AcceptedPlan类的属性来读取计划的细节。当我不得不开始向详细信息表中插入新行时,我的问题出现了。从我的阅读中,似乎创建新子对象的唯一方法是将其添加到父对象,然后保存会话。但是,每次我想创建新的详细记录时,我都不想创建新的父计划对象。这似乎是不必要的开销。有谁知道我是否以错误的方式解决这个问题?
答案 0 :(得分:3)
我不会让子对象包含他们的逻辑父对象,当你这样做时,它会很快变得非常混乱和非常快速递归。在你做这类事之前,我会先看看你打算如何使用领域模型。您可以轻松地在表格中使用ID引用,并将它们保留为未映射。
以下两个示例映射可能会在正确的方向上推动您,我必须使用adlib表名等,但它可能会有所帮助。我可能还建议将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 :(得分:1)
在我写作的时候没有看到你的数据库图表。
<?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>
应该可以做到这一点(我只为集合做了示例映射,你必须添加其他属性)。
答案 2 :(得分:0)
我对此进行建模的方法如下:
客户对象包含ICollection&lt; PaymentPlan&gt; PaymentPlans代表客户已接受的计划。
客户的PaymentPlan将使用包来映射,该包使用详细信息表来确定哪个客户ID映射到哪个PaymentPlans。使用cascade all-delete-orphan,如果客户被删除,详细信息条目和客户拥有的PaymentPlans都将被删除。
PaymentPlan对象包含一个PlanTerms对象,表示付款计划的条款。
PlanTerms将使用多对一映射级联保存更新映射到PaymentPlan,这只会将相关PlanTerms对象的引用插入到PaymentPlan中。
使用此模型,您可以独立创建PlanTerms,然后在向客户添加新的PaymentPlan时,您将创建一个新的PaymentPlan对象,传递相关的PlanTerms对象,然后将其添加到相关客户的集合中。最后,您将保存客户并让nhibernate级联保存操作。
您最终会得到一个Customer对象,一个PaymentPlan对象和一个PlanTerms对象,其中Customer(客户表)拥有PaymentPlans实例(详细信息表),这些实例都是特定的PlanTerms(计划表)。
如果需要,我有一些更具体的映射语法示例,但最好是使用您自己的模型进行处理,而且我没有足够的数据库表信息来提供任何具体示例。
答案 3 :(得分:0)
我不知道这是否可能是因为我的NHibernate体验有限,但是你可以创建一个BaseDetail类,它只有Details的属性,因为它们直接映射到Detail表。
然后创建第二个类,该类继承自具有附加父计划对象的BaseDetail类,因此当您只想创建一个Detail行并将PlanId分配给它时,可以创建一个BaseDetail类,但是如果需要填充带有父计划对象的完整详细记录,您可以使用继承的详细信息类。
我不知道这是否有多大意义,但请告诉我,我会进一步澄清。
答案 4 :(得分:0)
我认为你在这里遇到的问题是你的AcceptedOffer对象包含一个Plan对象,然后你的Plan对象似乎包含一个包含AcceptedOffer对象的AcceptedOffers集合。与客户一样。我认为,物体是彼此的孩子的事实是导致你的问题的原因。
同样,使您的AcceptedOffer复杂的原因是它有两个职责:它表示计划中包含的要约,表示客户接受。这违反了单一责任原则。
您可能必须区分计划下的要约和客户接受的要约。所以这就是我要做的事情:
我认为这将充分解开您的NHibernate映射和对象保存问题。 :)
答案 5 :(得分:0)
可能(或可能不)在NHibernate中有用的提示:您可以将对象映射到Views,就像View是一个表一样。只需将视图名称指定为表名;只要视图和映射中包含所有NOT NULL字段,它就可以正常工作。