I am trying to persist an object with a collection of child objects. I can’t persist the children first as there is a FK relationship. I could save the parent first and then add the children on to it, but this would introduce more work. Basically I’m just trying to save a fully populated object in one step and not break it into parts. Is there something wrong with my mapping (sorry it looks so ugly) or is it my methods?
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>
Child:
<?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>
Here’s my 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.
I get this when my test below tries to add an orderdetail to the order while it is still transient:
[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(); }
Specify cascading on the collection, and let NHibernate figure it out for you
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
Okay, I’ve seen that you’ve done that. 🙂 What you haven’t done, is specify the back-reference. I mean: you add an item to your collection, but this added item has a property to its owner, which you haven’t set:
What would be even better (imho) is this (simplified) :