views:

52

answers:

2

Hell All, ** Solved as of now Please see Edit 2 and Edit 3 **

I am NHibernate Newbie- a week old but I though working with it will save me time on new project and not otherwise. I have been banging my head trying to get Nhibernate to save Parent - Child Collection to SQL server database.

alt text

My Class Map :

 public class OrderMap : ClassMap<Order>
    {
        public OrderMap()
        {
            Table("orders");
            Not.LazyLoad();
            Id(x => x.Id,"id");
            Map(x => x.Status, "status").CustomType(typeof(OrderStatus)).Not.Nullable();
            Map(x => x.PurchaseOrder, "purchaseorder").Not.Nullable();
            Map(x => x.SalesOrder, "salesorder").Not.Nullable();
            Map(x => x.SupplierLocationId, "shipfrom").Not.Nullable();
            Map(x => x.CustomerLocationId, "shipto").Not.Nullable();
            Map(x => x.TypeOfShipment, "shipmenttype").CustomType(typeof (ShipmentType)).Not.Nullable();
            HasMany(x => x.OrderLineItems).Table("orderitems").KeyColumns.Add("orderid").Cascade.All(); 



        }
    }

public class OrderLineMap : ClassMap { public OrderLineMap() { Table("orderitems");

    Not.LazyLoad();
    Id(x => x.Id,"id");
    Map(x => x.Order.Id, "orderid").Not.Insert().Not.Update();
    Map(x => x.PartNumber, "partnumber");
    Map(x => x.LineNumber, "linenumber");
    Map(x => x.ReleaseNumber, "releasenumber");
    Map(x => x.Quantity, "quantity");
    Map(x => x.AttachedQuantity, "attached");
    Map(x => x.ActivatedQuantity, "activated");
    Map(x => x.ReshippedQuantity, "reshipped");
    Map(x => x.ReturnRequestQuantity, "requestreturn");
    Map(x => x.ReturnedToSupplierQuantity, "returnedtosupplier");
    Map(x => x.ReturnedFromResellerQuantity, "returnedfromreseller");
    Map(x => x.SplitQuantity, "split");
    Map(x => x.CombineQuantity, "combine");
    Map(x => x.Status, "status").CustomType(typeof(OrderLineStatus));
    Map(x => x.ReferenceOrderId, "reforderid");
    Map(x => x.ReferenceOrderLineId, "reforderlineid");         
    References(oi => oi.Order, "id");

}

}

I am trying to do a Has Many operation. Now I was made to believe (from lot of other posts in SO and Blogs) that it is not possible unless I have a Orders class reference in OrderItems

alt text

I am doing testing through Nunit and NH Profiler and insert statement for orders is getting profiled...

OrderTesting.CreateNewOrder : FailedNHibernate.StaleStateException : Unexpected row count: 0; expected: 1
at NHibernate.AdoNet.Expectations.BasicExpectation.VerifyOutcomeNonBatched(Int32 rowCount, IDbCommand statement)
at NHibernate.AdoNet.NonBatchingBatcher.AddToBatch(IExpectation expectation)
at NHibernate.Persister.Collection.AbstractCollectionPersister.PerformInsert(Object ownerId, IPersistentCollection collection, IExpectation expectation, Object entry, Int32 index, Boolean useBatch, Boolean callable, ISessionImplementor session)
at NHibernate.Persister.Collection.AbstractCollectionPersister.Recreate(IPersistentCollection collection, Object id, ISessionImplementor session)
at NHibernate.Action.CollectionRecreateAction.Execute()
at NHibernate.Engine.ActionQueue.Execute(IExecutable executable)
at NHibernate.Engine.ActionQueue.ExecuteActions(IList list)
at NHibernate.Engine.ActionQueue.ExecuteActions()
at NHibernate.Event.Default.AbstractFlushingEventListener.PerformExecutions(IEventSource session)
at NHibernate.Event.Default.DefaultFlushEventListener.OnFlush(FlushEvent event)
at NHibernate.Impl.SessionImpl.Flush()
at NHibernate.Transaction.AdoTransaction.Commit()
at Repository.OrderRepository.Save(Order entity) in OrderRepository.cs: line 30

Any help will be appreciated on how to solve it.

Thank you,

Mar

Edit: Update statement now seen in NH profiler after making changes as Joseph asked:

UPDATE orderitems
SET    partnumber = 670712 /* @p0 */,
       linenumber = 1 /* @p1 */,
       releasenumber = 1 /* @p2 */,
       quantity = 2 /* @p3 */,
       attached = 0 /* @p4 */,
       activated = 0 /* @p5 */,
       reshipped = 0 /* @p6 */,
       requestreturn = 0 /* @p7 */,
       returnedtosupplier = 0 /* @p8 */,
       returnedfromreseller = 0 /* @p9 */,
       split = 0 /* @p10 */,
       combine = 0 /* @p11 */,
       status = 0 /* @p12 */,
       reforderid = '00000000-0000-0000-0000-000000000000' /* @p13 */,
       reforderlineid = '00000000-0000-0000-0000-000000000000' /* @p14 */,
       orderid = NULL /* @p15 */
WHERE  id = '66f8c7c6-ece6-47c6-93f0-b8e1975a96dc' /* @p16 */

Edit 2 Resolution for Update Statements

IN the Child Class Map change Id(x => x.Id, "id").GeneratedBy.Assigned().UnsavedValue(null);

Edit 3 Improve inserts

Based on the above code NH profiler will show that for each object instance being persisted it will first generate a select statement based on which, it will determine if the object instance is new or dirty. To avoid it use Interceptor as

http://www.kkaok.pe.kr/doc/hibernate/reference/html/example-parentchild.html

Navigate to the very bottom of the article where you will find about how to implement Interceptor. Persistent class will be your base class for your Entities that needs to be saved to database. Interceptor will need to be registered firing the session

I have read that Interceptors have been replaced by events. Could not read a lot on it but Interceptor works great for me.

+2  A: 

You shouldn't need this line

Map(x => x.Order.Id, "orderid").Not.Insert().Not.Update();

I think that might be messing you up.

Also, when you reference your Order, you need to give it the name of the foreign key field, which it looks like you don't have right now.

so you should have this

References(oi => oi.Order, "orderid");
Joseph
@Joseph- the whole line or just ).Not.Insert().Not.Update();
TheMar
@The whole line, because FNH will infer the ID from your References line.
Joseph
@joseph- after doing what you asked above I am getting the same error, but now in NH profiler I am able to that an update statement is being sent. PLease see the edit section above where I have added the update statement.
TheMar
It looks like your not setting the order on your order item
Joseph
@Joseph- I am passing the order and setting the Order Property (in constructor)
TheMar
@Joseph- Sorry You were right, I was not setting the order to Order but rather order.id to OrderId property. I have changed it and now I see that OrderID is no longer null but that of the prder I am passing. Thank you for making me aware of this. ANy reason why NH generates Update statement instead of Insert for child collections
TheMar
I believe NH will track for you whether or not to do an update or an insert.
Joseph
Joseph- I think the problem is because of assigned Id. This seems to be solved if we add Version to the mapping. Any idea how this can be done
TheMar
Finally I was able to get it right - I declares explicitly that the ID is assigned i.e. Id(x => x.Id, "id").GeneratedBy.Assigned().UnsavedValue(null); The issue is with NH to find if the records are new or old.
TheMar
Oh I see, you wanted to be able to assign the ID yourself. By default NH tries to do that for you.
Joseph
A: 

Shouldn't your OrderLineMap class have this:

References(oi => oi.Order, "orderid")

instead of this: References(oi => oi.Order, "id") ?

SquidScareMe
@SquidScareMe- I have added this line after Joseph pointed the same
TheMar