views:

26

answers:

2

I have a class, BillMedicine, which is many-to-many table for Bill and Medicine. The BillMedicine mapping file is:

<class name="BillMedicine" table="Bill_Medicine">
    <composite-id>
        <key-many-to-one name="Bill" class="Bill" column="BillID" />
        <key-many-to-one name="Medicine" class="Medicine" column="MedicineID" />
    </composite-id>
    <version name="LastModifiedOn" column="LastModifiedOn" type="DateTime" 
             access="field.pascalcase-underscore" />
    <property name="Quantity" column="QuantityPurchased" />
</class>

When I create a new BillMedicine and update the quantity my unit test succeeds. However if I uncomment the line that updates the medicine, I got the exception NHibernate.StaleObjectStateException: Row was updated or deleted by another transaction

BillMedicineRepository target = new BillMedicineRepository();
BillMedicine billMedicine =
    new BillMedicine { Bill = _bill, Medicine = _medicine1, Quantity = 1 };
target.AddBillMedicine(billMedicine);

//billMedicine.Medicine = _medicine2;
billMedicine.Quantity = 2;
target.UpdateBillMedicine(billMedicine); // Exception if I update the medicine

I have checked the SQL shown by NHibernate and it is not updating the medicine

UPDATE Bill_Medicine SET LastModifiedOn = @p0, QuantityPurchased = @p1
WHERE BillID = @p2 AND MedicineID = @p3 AND LastModifiedOn = @p4;

Edit:

My Questions:
1- Why updating the quantity only is working but updating the medicine is throwing exception?
2- Is it possible to make Nhibernate update the medicine property? If yes, how? If no, can someone suggest a workaround?

A: 

I think you should create another object, because i have a deja-vu here. Your trying to

  1. create an object with the key B1 M1
  2. save it
  3. keeping the same object and same reference, changing the key to B1 M2
  4. updating the new object (with an old reference)

I'd recommend either flushing your session between the save and the update, or using a transaction for each of the operations (flushing should be enough though, i recommend the transaction only because it's a good practice :) ). I have the feeling you're trying to update an object that hasn't been inserted yet

samy
In AddBillMedicine and UpdateBillMedicine, I am saving/updating using a new transaction. I have also tried to add session.Flush but in vain. The point is if I update the quantity only the update succeeds however if I update the medicine the update fails.
sh_kamalh
Also I am not updating a new obejct, I am updating the object I have just saved.
sh_kamalh
sh_kamath: it's a new object in the sense that its key is different. In a database like this B1M1 and B1M2 should be different objects
samy
If you consider the primary keys of the table then your comment correct. But the query generated by NHibernate is updating the Bill_Medicine table so it seems that NHibernate is aware that this object is already inserted in the database.
sh_kamalh
+2  A: 

NHibernate does not allow changing the primary key.

Possible workarounds:

  • Create a new instance with the new medicine and delete the old one
  • Use an HQL update to change the Medicine. Keep in mind that the in-memory state won't match the DB unless you Evict the instance and load it again.
Diego Mijelshon
How can I get the old medicine ID? Let's say that I have already changed the medicine property, can I get the old medicien?
sh_kamalh
Just store it in a variable.......
Diego Mijelshon