Fluent Nhibernate : Unexpected row count: 0; expected: 1

fluent-nhibernatehas-manynhibernate

** 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<OrderLine>
{
    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 the ID line to:

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.

Best Answer

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");