Hi All,
I have a collection of objects in a class which I cascade using save-update. The collection also has a read-write cache associated with it.
I DO NOT cascade deletes via the collection as due to specific requirements in my app If an object is being referenced as a foreign key in the database I have some specific logic to inactivate it, but it still is removed from the collection.
Here is where it gets weird, If I instantiate an instance of the class (Lpcorganization), load the Positions collection (which caches the collection) and do a separate delete at that point, I can evict the Positions collection from the second level cache and it works fine.
But ... if, I instantiate an instance of Lpcorganization, load the Positions collection, ADD a new postion to the collection (which is successful) and then perform the delete, after the eviction of the collection from the second level cache I get a lazy load exception (pasted below) saying that the object with the id that I deleted is no longer in the database.
So, for some reason if I add objects to the collection, either the EvictCollection call on the cache does not properly evict the collection, or a reference to the colection has been added to the cahce in a region which I am unaware of.
One final item, as a test, if I set the cascade on the collection to all-delete-orphan, and do the delete via the collection, it works fine before and after an add ...... the cache updates itself correctly an on the next lazy load of the collection the deleted item has been removed.
There seem to be a few posting on the cache and evicting, are there other cache regions created for collections other than the classname + property one (rolename in the source) which I am not aware of?
Any help on this would really be appreciated ... as it is, I can use the cache for read-only collections and it seems for collections with cascade all-delete-orphan, but I cannot have a collection which references related objects which are maintained in a different part of the system ....
I have alot of data which falls in this last category, it is maintained elsewhere in the system and in all probability will not be updated often, but when it is, I obviouusly have to be able to force any cached references to that data to be destroyed and re-queried.
Hibernate version:
1.0.2
Mapping documents:
Class which contains the collection
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.0" schema="dbo" default-cascade="save-update" auto-import="false" default-access="field.pascalcase-m-underscore">
<class name="xwave.NMR.DL.DTO.Lpcorganization, DataAccess" table="LPC_ORGANIZATIONS" >
<cache usage="read-write"/>
<id name="Id" type="Decimal" column="LPC_ORG_ID" unsaved-value="0">
<generator class="identity" />
</id>
<timestamp name="LastUpdated" column="LAST_UPDATED"/>
<property name="Active" column="ACTIVE" type="Boolean" />
<property name="Order" column="LPC_ORGANIZATION_ORDER" type="Int16" />
<property name="en" column="VALUE_EN_CA" type="String" />
<property name="fr" column="VALUE_FR_CA" type="String" />
<property name="OrganizationType" column="ORG_TYPE_ID" type="Decimal" />
<bag name="LPCOrganizationalGroups" table="ORGANIZATION_GROUPS" lazy="true" cascade="all-delete-orphan">
<cache usage="read-write"/>
<key column="ORGANIZATION_ID"/>
<one-to-many class="xwave.NMR.DL.DTO.Organizationgroup, DataAccess"/>
</bag>
<bag name="Positions" table="LPC_ORGANIZATION_POSITIONS" lazy="true" cascade="save-update">
<cache usage="read-write"/>
<key column="LPC_ORG_ID" />
<one-to-many class="xwave.NMR.DL.DTO.LPCOrganizationPosition, DataAccess" />
</bag>
</class>
</hibernate-mapping>
LPCOrganizationPosition
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.0" schema="dbo" default-cascade="save-update" auto-import="false" default-access="field.pascalcase-m-underscore">
<class name="xwave.NMR.DL.DTO.LPCOrganizationPosition, DataAccess" table="LPC_ORGANIZATION_POSITIONS">
<cache usage="read-write"/>
<id name="Id" column="LPC_ORG_POSITION_ID" type="Decimal">
<generator class="identity"/>
</id>
<timestamp name="LastUpdated" column="LAST_UPDATED"/>
<many-to-one name="LPCOrganization" column="LPC_ORG_ID" class="xwave.NMR.DL.DTO.Lpcorganization, DataAccess"/>
<property name="Active" column="ACTIVE" type="Boolean" />
<property name="Directory" column="DIRECTORY" type="Int16" />
<many-to-one name="Positiontitle" column="POSITION_TITLE_ID" class="xwave.NMR.DL.DTO.Positiontitle, DataAccess" cascade="none"/>
<property name="Singleposition" column="SINGLE_POSITION" type="Boolean" />
<property name="en" column="DESCRIPTION_EN_CA" type="String" not-null="true"/>
<property name="fr" column="DESCRIPTION_FR_CA" type="String" not-null="true"/>
<bag name="PositionsHeld" lazy="true" table="POSITION_HELD" cascade="none" where="held_to is null">
<!--<cache usage="read-write"/>-->
<key column="LPC_ORG_POSITION_ID"/>
<one-to-many class="xwave.NMR.DL.DTO.PositionHeld, DataAccess"/>
</bag>
<bag name="AllPositionsHeld" lazy="true" table="POSITION_HELD" cascade="none">
<cache usage="read-write"/>
<key column="LPC_ORG_POSITION_ID"/>
<one-to-many class="xwave.NMR.DL.DTO.PositionHeld, DataAccess"/>
</bag>
<bag name="OrganizationalGroupPositions" lazy="true" table="ORGANIZATIONAL_GROUP_POSITIONS" cascade="none">
<cache usage="read-write"/>
<key column="LPC_ORG_POSITION_ID"/>
<one-to-many class="xwave.NMR.DL.DTO.OrgGroupPosition, DataAccess"/>
</bag>
</class>
</hibernate-mapping>
Code between sessionFactory.openSession() and session.close():
test Code which works:
Lpcorganization lpco = (Lpcorganization) session.Get(typeof(Lpcorganization),(decimal) 1);
//obviously this position must be in the collection
LPCOrganizationPosition lpcop = (LPCOrganizationPosition) session.Get(typeof(LPCOrganizationPosition),(decimal) 1);
ITransaction trans = session.BeginTransaction();
session.Delete(lpcop);
trans.Commit();
sessionFactory.EvictCollection("xwave.NMR.DL.DTO.Lpcorganization.Positions");
//this lazy load of the collection will work
foreach (LPCOrganizationPosition pos in lpco.Positions){
}
test code which doesn't work:
Lpcorganization lpco = (Lpcorganization) session.Get(typeof(Lpcorganization),(decimal) 1);
/////////////////// this is the new part ///////////////
LPCOrganizationPosition lpcop = new LPCOrganizationPosition();
//set some of the properties
lpcop.en="hi";
lpcop.fr="fr";
lpco.Positions.Add(lpcop);
ITransaction trans = session.BeginTransaction();
session.SaveOrUpdate(lpco);
trans.Commit();
//////////////// end of new part ///////////////////////////////
ITransaction trans = session.BeginTransaction();
session.Delete(lpcop);
trans.Commit();
sessionFactory.EvictCollection("xwave.NMR.DL.DTO.Lpcorganization.Positions");
//now, the lazy load throws the exception below .....
foreach (LPCOrganizationPosition pos in lpco.Positions){
}
Full stack trace of any exception that occurs:
2006-03-31 16:49:57,661 [2900] ERROR xwave.NMR.Web.UI.PageFramework.NMRPageBaseHelper [(null)] <(null)> - NMR Page Error Occurred:
NHibernate.LazyInitializationException: Failed to lazily initialize a collection ---> NHibernate.UnresolvableObjectException: No row with the given identifier exists: 4418, of class: xwave.NMR.DL.DTO.LPCOrganizationPosition
at NHibernate.UnresolvableObjectException.ThrowIfNull(Object o, Object id, Type clazz)
at NHibernate.Impl.SessionImpl.InternalLoad(Type clazz, Object id)
at NHibernate.Type.ManyToOneType.ResolveIdentifier(Object id, ISessionImplementor session)
at NHibernate.Type.ManyToOneType.Assemble(Object oid, ISessionImplementor session, Object owner)
at NHibernate.Collection.Bag.InitializeFromCache(ICollectionPersister persister, Object disassembled, Object owner)
at NHibernate.Impl.SessionImpl.InitializeCollectionFromCache(Object id, Object owner, ICollectionPersister persister, PersistentCollection collection)
at NHibernate.Impl.SessionImpl.InitializeCollection(PersistentCollection collection, Boolean writing)
at NHibernate.Collection.PersistentCollection.Initialize(Boolean writing)
--- End of inner exception stack trace ---
at NHibernate.Collection.PersistentCollection.Initialize(Boolean writing)
at NHibernate.Collection.PersistentCollection.Read()
at NHibernate.Collection.Bag.GetEnumerator()
at xwave.NMR.Web.Maintain.PositionDefinitions.Listing.LoadPositionData() in c:\inetpub\wwwroot\nmrwebapp\maintain\position_definitions\listing.aspx.cs:line 127
at xwave.NMR.Web.Maintain.PositionDefinitions.Listing.OnColumnButton_Click(Object sender, DataGridCommandEventArgs e) in c:\inetpub\wwwroot\nmrwebapp\maintain\position_definitions\listing.aspx.cs:line 155
at System.Web.UI.WebControls.DataGrid.OnItemCommand(DataGridCommandEventArgs e)
at System.Web.UI.WebControls.DataGrid.OnBubbleEvent(Object source, EventArgs e)
at System.Web.UI.Control.RaiseBubbleEvent(Object source, EventArgs args)
at System.Web.UI.WebControls.DataGridItem.OnBubbleEvent(Object source, EventArgs e)
at System.Web.UI.Control.RaiseBubbleEvent(Object source, EventArgs args)
at System.Web.UI.WebControls.ImageButton.OnCommand(CommandEventArgs e)
at System.Web.UI.WebControls.ImageButton.System.Web.UI.IPostBackEventHandler.RaisePostBackEvent(String eventArgument)
at System.Web.UI.Page.RaisePostBackEvent(IPostBackEventHandler sourceControl, String eventArgument)
at System.Web.UI.Page.RaisePostBackEvent(NameValueCollection postData)
at System.Web.UI.Page.ProcessRequestMain()
Name and version of the database you are using:
SQL Server 2000 sp4
|