NHibernate Caching and Assigned Ids - A Potential Pitfall

Yesterday, I spent some time setting up and optimizing SysCache2 caching.  (By the way, if you're doing this kind of NHibernate tuning, NHProf - a devlicio.us friend - is crucial, it would have definitely been a much tougher slog without it) With caching turned on, one of our previously well-functioning classes was consistently giving the following error EVERY time we tried to modify and save an instance:

ReadOnlyCache: Can't write to a readonly object

Looking this up, I ran across a LOT of information about how this meant the cache line in the mapping was wrong - that it needed to be marked read-write, not read-only.  The odd thing was, this is what the cache line in our mapping was like already:

<cache usage="read-write" region="SomeRegion" />

So, our problem was NOT the obvious issue that our object was improperly marked as readonly.  But... after a lot of flailing around, the solution emerged.  Check out this definition of the ID on this entity:

    <id name="Id" column="EntityID" type="Int32" unsaved-value = "0">
      <generator class="assigned" />
    </id>

Note the use of "assigned" for the id generator.  It means NHibernate doesn't control the id-it's manually managed. Now if you're familiar with the assigned generator, you know that it's a somewhat troublesome thing to work with-specifically, if you call SaveOrUpdate on an entity using it, NHibernate won't know whether it's a new entity or not on its own, because NHibernate tracks the state of the entiy using the id.  This affects cascade saves as well, so assigned ids aren't fun. If you take over managing that id yourself, NHibernate doesn't have anything to hang its tracking off of.  Assigned ids are something you should probably avoid for new applications, but  sometimes that's not an option  for legacy apps.... If you NEED to use an assigned id there's an easy way to get this entity acting like a normal NHibernate entity-you can give NHibernate something to use like this:

<version name="LastModifiedOn" type="timestamp" column="LastModifiedOn"    />
-with the matching column, and the matching property in the class - or maybe even just using the access="field.." option in the mapping so it's not mistakenly taken to be something to be part of the class's regular api by another programmer-this field is NOT FOR YOU, it's for NHibernate. Look at it if you want, but do not touch! Note that if you add a column like this to an existing table, you're going to have to prepopulate the existing rows for your your new column with an initial datetime or you'll get errors-any date at all, so long as it's in the past. 1/1/2009 12:00:00 is as good a value as any....

What does this have to do with my caching problem?  The particular entity I was getting the erroneous readonly caching  problems on didn't have the <version> property-a bad state of things for an assigned id entity.  Oddly, it *was* in fact saving properly using SaveOrUpdate - perhaps it was the unsaved-value = "0" on the id allowing it to work, maybe not.  Anyway, the solution ended up being adding a <version> property and column, and then it worked like a charm. I probably should have caught that this entity was missing <version> earlier, but it seemed to work ok, and the potential problem stayed hidden until the entity got thrown into the cache.

By the way, if you don't like  <version>, there are alternatives, like IInterceptor.IsTransient()


Posted 10-08-2009 8:53 AM by Anne Epstein
Filed under: ,

[Advertisement]

Comments

Dipen wrote re: NHibernate Caching and Assigned Ids - A Potential Pitfall
on 07-08-2010 6:46 AM

Actually you dont have to do so many things. Check the region of cache

<cache usage="read-write" region="SomeRegion" />

This SomeRegion should be used for only read-write on other Entity also. May be other entity also uses SomeRegion which has read-only cache usage.

Anne Epstein wrote re: NHibernate Caching and Assigned Ids - A Potential Pitfall
on 07-12-2010 9:32 PM

Dipen, The thing is, everything else equal, caching works great when the entity ID type  is *NOT* assigned  (i.e. it's either DB-generated or NHibernate-generated)... though the error message  might be the same in the situation you described, the  problem described is specific to assigned-type IDs-if you change the ID type, the described error disappears; when set up properly, a region can contain entities with any type of ID, and the region works well with both read-only and read-write entities (or, if not, that is a concern orthogonal to that discussed in this post).  The problem described above isn't the cache type, it's the change tracking, and an assigned id (including composite keys, which are really a special subset of assigned key) messes with that.

joe wrote re: NHibernate Caching and Assigned Ids - A Potential Pitfall
on 02-24-2011 7:37 AM

check this link, its also a very good read about NHibernate L2 caching

www.alachisoft.com/.../nhibernate_l2cache_index.html

Coltin wrote re: NHibernate Caching and Assigned Ids - A Potential Pitfall
on 10-10-2011 3:14 AM

Yup, that shluod defo do the trick!

link building wrote re: NHibernate Caching and Assigned Ids - A Potential Pitfall
on 07-18-2014 5:28 PM

ylOFii Thanks so much for the blog article.Much thanks again. Much obliged.

crokrz linkz wrote re: NHibernate Caching and Assigned Ids - A Potential Pitfall
on 12-17-2014 7:21 PM

Fmdlbu Im grateful for the post.Really thank you! Great.

Add a Comment

(required)  
(optional)
(required)  
Remember Me?

About The CodeBetter.Com Blog Network
CodeBetter.Com FAQ

Our Mission

Advertisers should contact Brendan

Subscribe
Google Reader or Homepage

del.icio.us CodeBetter.com Latest Items
Add to My Yahoo!
Subscribe with Bloglines
Subscribe in NewsGator Online
Subscribe with myFeedster
Add to My AOL
Furl CodeBetter.com Latest Items
Subscribe in Rojo

Member Projects
DimeCasts.Net - Derik Whittaker

Friends of Devlicio.us
Red-Gate Tools For SQL and .NET

NDepend

SlickEdit
 
SmartInspect .NET Logging
NGEDIT: ViEmu and Codekana
LiteAccounting.Com
DevExpress
Fixx
NHibernate Profiler
Unfuddle
Balsamiq Mockups
Scrumy
JetBrains - ReSharper
Umbraco
NServiceBus
RavenDb
Web Sequence Diagrams
Ducksboard<-- NEW Friend!

 



Site Copyright © 2007 CodeBetter.Com
Content Copyright Individual Bloggers

 

Community Server (Commercial Edition)