2009-04-06 5 views
1

J'essaie de persister un objet avec une collection d'objets enfants. Je ne peux pas persister les enfants d'abord car il y a une relation FK. Je pourrais d'abord sauver le parent, puis ajouter les enfants, mais cela entraînerait plus de travail. Fondamentalement, je suis juste en train d'essayer de sauver un objet entièrement peuplé en une seule étape et ne pas le diviser en plusieurs parties. Y at-il quelque chose qui ne va pas avec ma cartographie (désolé, il semble si laid) ou est-ce mes méthodes?NHibernate: Persist un objet avec des enfants

Parent:

<?xml version="1.0" encoding="utf-8" ?> 
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"> 
    <class name="NetworkOrderManagement.Core.Order, NetworkOrderManagement.Core" table="NETORDMGMT.ORDERHEADER" lazy="false" > 
    <id name="OrderId" column="ORDERID" type="int"> 
     <generator class="seqhilo"> 
     <param name="sequence">ORDERID_SEQ</param> 
     </generator> 
    </id> 
    <property name="TransmissionDate" column="TRANSMISSIONDATE" type="DateTime"/> 
    <property name="StoreNumber" column="STORENUMBER" type="Int16"/> 
    <property name="Department" column="DEPARTMENT" type="Int16"/> 
    <property name="OrderType" column="ORDERTYPE" type="Int16"/> 
    <property name="OrderSequence" column="ORDERSEQUENCE" type="Int16"/> 
    <property name="ExtractTime" column="EXTRACTTIME" type="DateTime"/> 
    <property name="Status" column="STATUS" type="Int16"/> 
    <property name="ReceivedTime" column="RECEIVEDTIME" type="DateTime"/> 
    <bag name="OrderDetail" table="NETORDMGMT.ORDERDETAIL" 
     lazy="false" cascade="all" inverse="true"> 
     <key column="ORDERID" on-delete="cascade"/> 
     <one-to-many class="NetworkOrderManagement.Core.OrderDetail, NetworkOrderManagement.Core" /> 
    </bag> 
    </class> 
</hibernate-mapping> 

enfant:

<?xml version="1.0" encoding="utf-8" ?> 
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"> 
    <class name="NetworkOrderManagement.Core.OrderDetail, NetworkOrderManagement.Core" table="NETORDMGMT.ORDERDETAIL" lazy="false"> 
    <id name="OrderDetailId" column="ORDERDETAILID" type="int"> 
     <generator class="seqhilo"> 
     <param name="sequence">"ORDERDTLID_SEQ"</param> 
     </generator> 
    </id> 
<many-to-one name="Order" class="NetworkOrderManagement.Core.Order, NetworkOrderManagement.Core" 
       column="OrderId" lazy="false" not-null="true" /> 
    <property name="ItemNumber" column="ITEMNUMBER" type="Int32"/> 
    <property name="OrderQuantity" column="ORDERQUANTITY" type="Int32"/> 
    <property name="ErrorCode" column="ERRORCODE" type="Int32"/> 
    </class> 
</hibernate-mapping> 

Voici mon exception:

Test method NetworkOrderManagement.Tests.DataAccess.QuickTests.QuickTest threw exception: 
Distribution.Exceptions.DataAccessException: NHibernate Exception ---> 
NHibernate.PropertyValueException: not-null property references a null or transient valueNetworkOrderManagement.Core.OrderDetail.Order. 

je reçois quand mon test ci-dessous tente d'ajouter un OrderDetail à l'ordre alors qu'il est encore transitoire:

[TestMethod] 
    public void QuickTest() 
    { 
     myOrderRepository = NetworkOrderManagement.Data.RepositoryFactory.Instance.GetOrderRepository(); 
     myOrderDetailRepository = NetworkOrderManagement.Data.RepositoryFactory.Instance.GetOrderDetailRepository(); 
     myOrder = new Order { StoreNumber = RandGen.LittleRand(), Department = RandGen.LittleRand(), TransmissionDate = DateTime.MinValue, ExtractTime = DateTime.MinValue, ReceivedTime = DateTime.MinValue }; 
     myOrder = myOrderRepository.Save(myOrder); 

     myOrderDetail1 = new OrderDetail {OrderId = myOrder.OrderId, ItemNumber = RandGen.BigRand(), OrderQuantity = RandGen.LittleRand() }; 
     myOrderDetail2 = new OrderDetail {OrderId = myOrder.OrderId, ItemNumber = RandGen.BigRand(), OrderQuantity = RandGen.LittleRand() }; 
     myOrderDetail1 = myOrderDetailRepository.Save(myOrderDetail1); 
     myOrderDetail2 = myOrderDetailRepository.Save(myOrderDetail2); 
     myOrder.OrderDetail.Add(myOrderDetail1); 
     myOrder.OrderDetail.Add(myOrderDetail2); 

     myOrderRepository.CommitChanges(); 

     myOrderDetailRepository.Delete(myOrderDetail2); 
     myOrderRepository.CommitChanges(); 
     myOrderRepository.Delete(myOrder); 
     myOrderRepository.CommitChanges(); 
    } 

Répondre

6

en cascade sur la Spécifiez collection, et laissez-le figurer NHibernate pour vous

http://ayende.com/Blog/archive/2006/12/02/NHibernateCascadesTheDifferentBetweenAllAlldeleteorphansAndSaveupdate.aspx

http://www.hibernate.org/hib_docs/nhibernate/1.2/reference/en/html/example-parentchild.html

D'accord, je l'ai vu que vous avez fait cela. :) Ce que vous n'avez pas fait est de spécifier la référence arrière. Je veux dire: vous ajoutez un élément à votre collection, mais cet article ajouté a une propriété à son propriétaire, que vous n'avez pas défini:

Order o = new Order(); 

OrderDetail detail = new OrderDetail(); 

detail.Order = o; 
o.OrderLines.Add (detail); 

Ce qui serait encore mieux (AMHA) est ce (simplifié) :

public class Order 
{ 
    private IList<OrderDetail> _details = new List<OrderDetail>(); 

    public ReadOnlyCollection<OrderDetail> Details 
    { 
     return new List(_details).AsReadOnly(); 
    } 

    public void AddOrderLine(OrderDetail d) 
    { 
     d.Order = this; 
     _details.Add (d); 
    } 

    public void RemoveOrderLine(OrderDetail d) 
    { 
     _details.Remove (d); 
    } 
} 
+0

Bien travaillé, merci de votre contribution! –

Questions connexes