Question : Nhibernate cache problem while using MS-SQL triggers

Hey!

I am using Nhibernate with Fluent, to persist a MS SQL 2008 express database in a business application.

I have a class named Receipt which contains a list with many objects named ReceiptItems.
The user can create a receipt, add Receiptitems to it, and edit it as long as its not marked Finished.
This part works well and saves to the db correctly.
Now for the problem:

I also have a trigger on the sql  table Receipt, that fires if the inserted.Finished is true.
The trigger fetches new prices from the  "supplier table", and updates the prices for all  ReceiptItems,
in the ReceiptItems table.

When calling
session.SaveorUpdate(value)
and then
transaction.Commit()

the latter  causes the exception:
StaleObjectStateException
Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) in ReceiptItems



Removing the trigger ofcourse fixes the problem, but i need it to update the prices. Is there any way for nhibernate to ignore the
error, and refresh its cache after the trigger fires?




straightforward class example definitions with Fluent mappings:

1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
 public class Receipt
    {

        public Receipt() { }
        /// <summary>Identificator/// </summary>
        public virtual int Id { get; private set; }
        /// <summary> if finished true, cant edit data/// </summary>
        public virtual Boolean Finished { get; set; }
        /// <summary>Items of this Receipt/// </summary>
        public virtual IList<ReceiptItems> Items{ get; set; }
    }

    /// <summary>Mapping for NHibernate Fluent/// </summary>
    public class ProdajaMap : ClassMap<Prodaja>
    {
       
        public ReceiptMap()
        {
            Table("Receipt");
            OptimisticLock.All();
            DynamicUpdate();
            Id(x => x.Id);
            Map(x => x.Finished);
            HasMany<ReceiptItems>(x => x.Items).AsBag().KeyColumn("Receipt_ID");
        }
    }


1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
public class ReceiptItem
    {

        public ReceiptItem() { }

        public virtual int Id { get; private set; }
        /// <summary>Id of the Receipt/// </summary>
        public virtual int Receipt_ID{ get; set; }

        /// <summary>Supplier price/// </summary>
        public virtual decimal Price{ get; set; }
        /// <summary>Supplier discount/// </summary>
        public virtual decimal Discount { get; set; }
    }

    /// <summary>Mapping for NHibernate Fluent/// </summary>
    public class ReceiptItemMap : ClassMap<ReceiptItem>
    {
        public ReceiptItemMap()
        {
            Table("ReceiptItems");
            OptimisticLock.All();
            DynamicUpdate();
            Id(x => x.Id);
            Map(x => x.Receipt_ID).Column("Receipt_ID");
            Map(x => x.Price);
            Map(x => x.Discount );

        }
    }



Thanks !


Answer : Nhibernate cache problem while using MS-SQL triggers

I wouldn't attempt to combine both triggers and the use of a data layer such as nhibernate - you're always going to get synchronisation problems. nHibernate is intended to manage your data - and your business layer should manage processes such as updating your prices. Personally I don't go near triggers for any business logic - for auditing perhaps, but nothing else. I think they obscure business logic and make it nigh on impossible to implement other code solutions for managing the data - as you are finding.
Why not move your trigger code into a stored procedure and call the procedure from within the transaction scope of the update if the 'finished' flag is true? I would manage this within the business layer, but you could move this to the data layer if you wish.

Tim
Random Solutions  
 
programming4us programming4us