2008-08-14 29 views
3

警告 - 我对NHibernate很新。我知道这个问题看起来很简单 - 我确信有一个简单的答案,但我已经在这个问题上旋转了一段时间。我正在处理一个真正无法在结构上改变的遗留数据库。我有一张详细列表,列出了客户已经接受的付款计划。每个付款计划都有一个ID,它链接回参考表以获取计划的条款,条件等。在我的对象模型中,我有一个AcceptedPlan类和一个Plan类。最初,我使用了从细节表返回到ref表的多对一关系来在NHibernate中建立这种关系。我还创建了一个从Plan类到AcceptedPlan类的相反方向的一对多关系。这很好,而我只是在读数据。我可以去我的计划对象,这是我的AcceptedPlan类的属性来阅读计划的细节。当我不得不开始向细节表插入新行时,出现了我的问题。从我的阅读中,似乎创建新的子对象的唯一方法是将其添加到父对象,然后保存会话。但我不想每次创建新的详细记录时都必须创建一个新的父级计划对象。这似乎是不必要的开销。有谁知道我是否以错误的方式解决这个问题?在处理遗留数据库时,在NHibernate中建立多对一关系的最佳方法?

回答

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

我会带模型,这是如下的方法:

Customer对象包含的ICollection <PaymentPlan> PaymentPlans代表客户所接受的方案。

客户的PaymentPlan将使用一个包使用详细信息表来确定哪个客户ID映射到哪个PaymentPlans。使用cascade all-delete-orphan,如果客户被删除,则细节条目和客户拥有的PaymentPlans都将被删除。

PaymentPlan对象包含一个PlanTerms对象,它代表了付款计划的条款。

PlanTerms将使用多对一映射级联保存更新映射到PaymentPlan,该保存更新只会将对相关PlanTerms对象的引用插入到PaymentPlan中。

使用此模型,您可以独立创建PlanTerms,然后当您向客户添加新的PaymentPlan时,您需要创建一个新的PaymentPlan对象,传入相关的PlanTerms对象,然后将其添加到相关客户的集合中。最后,您将保存客户并让nhibernate级联保存操作。

您最终将得到一个Customer对象,PaymentPlan对象和一个PlanTerms对象,其中Customer(Customer表)拥有PaymentPlans实例(详细信息表),它们都粘附到特定的PlanTerms(计划表)。

如果需要,我已经有了一些更具体的映射语法示例,但最好是使用您自己的模型来处理它,并且我没有足够的关于数据库表的信息来提供任何具体示例。

0

我不知道这是否可能是因为我的NHibernate体验有限,但是您可以创建一个BaseDetail类,该类只包含Details的属性,因为它们直接映射到Detail表。

然后创建第二个类,该类继承自具有其他父级计划对象的BaseDetail类,以便您可以在创建Detail行并将PlanId分配给它时创建BaseDetail类,但是如果需要使用Parent计划对象填充完整的Detail记录,您可以使用继承的Detail类。

我不知道这是否有很多意义,但让我知道,我会进一步澄清。

0

我认为你在这里遇到的问题是你的AcceptedOffer对象包含一个Plan对象,然后你的Plan对象看起来包含一个包含AcceptedOffer对象的AcceptedOffers集合。与客户同样的事情。我认为,物体是彼此的孩子的事实是导致你的问题的原因。

同样,什么使AcceptedOffer复杂是它有两个职责:它表示包含在计划中的提议,它表示接受客户。这违反了单一责任原则。

您可能不得不区分计划下的要约和客户接受的要约。因此,我要做的事情如下:

  1. 创建一个单独的Offer对象,该对象没有状态,例如,它没有客户并且没有状态 - 它只有一个OfferId和它所属的计划作为它的属性。
  2. 修改您的计划对象以获得一个Offers集合(它不必在其上下文中接受提议)。
  3. 最后,修改您的AcceptedOffer对象,以便它包含要约,客户和状态。客户保持不变。

我认为这将充分解决您的NHibernate映射和对象保存问题。 :)

0

可能(或可能不会)在NHibernate中有帮助的提示:您可以将对象映射到Views上,就像View是一张表一样。只需将视图名称指定为表名;只要所有的NOT NULL字段都包含在视图中并且它的映射工作正常。

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> 

应该可能做的伎俩(我只做了集合的示例映射,您将不得不添加其他属性)。

相关问题