3

I'm working on some code that is doing some moderately heavy data processing with NHibernate (yes, I know, perhaps not really the right tool for the job. But it's what I've got to work with)

I use a stateless session to get the first 1000 objects, check, update and add them to a list of updated objects if needed. I then repeat for the next 1000 objects until I'm done. Below is a significantly simplified version of the code.

List<MarketOrder> updated = new List<MarketOrder>();
IStatelessSession session = SessionProvider();
int offset = 0;
bool moreToGet = true;

while (moreToGet)
{
    var result = session.Query<MarketOrder>().Where(o => o.Owner.ID == currentEntityID && !o.Updated);
    var tmp = result.Skip(offset).Take(1000);

    foreach (MarketOrder item in data) 
    { 
        notUpdated.OrderState = MarketOrderState.Closed;
        updated.Add(notUpdated);
    }

    if (data.Count == pageSize) { offset += pageSize; }
    else { moreToGet = false; }
}

Another stateless session is then opened to do a bulk update

IStatelessSession session = SessionProvider();
foreach (MarketOrder o in updated) { session.Update(o); }

When I run my unit test, I get an error:

Test 'TestProcess_AutoCloseOrder' failed: NHibernate.PropertyValueException : Error         dehydrating property value for Data.Models.MarketOrder.Owner
---- NHibernate.PropertyAccessException : Exception occurred getter of Common.Models.ModelBase.Version
-------- System.Reflection.TargetInvocationException : Exception has been thrown by the target of an invocation.
------------ NHibernate.SessionException : proxies cannot be fetched by a stateless session

After some messing around, I figured that the error is because, in the Update, NHibernate is trying to access the Owner property of the MarketOrder being saved. (I assume this is to cascade the update) Owner is populated with a proxy and since it was loaded from a stateless session, cannot be accessed.

Sure enough, if I load from a regular session instead of a stateless session it all works fine. This solution will result in a performance hit in production though so I'd rather avoid it.

I could set Owner to not lazy load but that is not a practical solution for all similar cases.

The answer to this question: NHibernate: proxies cannot be fetched by a stateless session error message. Suggests fetching the problem property as part of the initial load but that seems very wasteful. I only want to update a few properties on the main object, why should I have to load all that object's child references as well?

What I want is for NHibernate to realise that only the main MarketOrder object has changed and not bother to cascade the update to Owner. In fact, now I think about it, I didn't think Stateless Session was supposed to cascade updates at all?

So anyone know what's going on here and how I can resolve it?

Community
  • 1
  • 1
Steve
  • 1,266
  • 16
  • 37
  • Can you FETCH owner in the first query? e.g. `session.Query().Fetch(f => f.Owner).Where` ... – Rippo Aug 15 '13 at 13:15
  • 1
    Yes, I just don't see why that should be necessary. It seems like an excessive overhead to fetch all my referenced objects just to change one or two simple properties on the main object. – Steve Aug 15 '13 at 13:34
  • Like it or not it may be your only solution if you want to stick with multiple sessions. – Rippo Aug 15 '13 at 13:39
  • I wonder if on second query just before update you can do `o.Owner = session.Load(o.Owner.Id);` as the `o.Owner.Id` will be available at this point and shouldn't force a proxy initialise. – Rippo Aug 15 '13 at 13:49
  • 1
    I tried just using a single session for load and update but still get the same problem. Perhaps I'm not being clear enough - I don't want to load this other entity. I shouldn't have to. If that's just the way NHibernate is then ok but I'm thinking I must just have it wrong since it seems remarkably odd to be forced to load entities that you're not going to do anything with. – Steve Aug 15 '13 at 14:40
  • Do you use versioning? Is this the cause of the error message – Rippo Aug 15 '13 at 14:45
  • I do use versioning. (simple int column that I let NHibernate handle) Surely if that was the problem then loading with a regular session would not have fixed it? – Steve Aug 15 '13 at 15:26
  • Does `MarketOrder` have a custom `Equals` or `GetHashCode` method that references `Owner`? – Daniel Schilling Aug 15 '13 at 22:18
  • @DanielSchilling No, it only has a `Clone` method – Steve Aug 16 '13 at 06:58

0 Answers0