Bizarre error when using NHibernate, IPreInsertEventListener, Oracle, batching and sequences

474 views
Skip to first unread message

Krzysztof Koźmic

unread,
May 6, 2011, 3:09:18 AM5/6/11
to nhu...@googlegroups.com
I'm using Oracle database.
I have a IPreUpdateEventListener and IPreInsertEventListener which set
CreatedBy and UpdatedBy properties on some of the entities.

Those properties point to another entity Person which is assigned in the
listeners via Session.Load<>

this all used to work quite nice when I had my POID generator specified
as "sequence-identity" (we use sequences in Oracle)

today I tried to switch POID generator to "sequence" which would allow
me to utilize batching which I also enabled.


Here's where I started getting this exception:

collection: [Person.FooBars] was not processed by flush()


the exception happens only when the Session.Load<> in my event listeners
doesn't already have the Person I'm requested accessible (that is only
when Load<Person> returns a proxy). If I load the person beforehand (and
not in the listener) the exception does not occur.


Any ideas what the reason for that is and how do I fix it?

Krzysztof

Fabio Maulo

unread,
May 6, 2011, 8:04:17 AM5/6/11
to nhu...@googlegroups.com
IPreUpdate is intended to be used for entity-state checking (veto) not to change the state.
What is happening is that NH found a strange operation in a collection (something like "somebody have changed it outside my control or I have a bug").
For what you need you have to use ISaveOrUpdateEventListener 
public void OnSaveOrUpdate(SaveOrUpdateEvent @event) 

var trackable = @event.Entity as ITrackModificationDate; 
if (trackable != null) 

trackable.LastModified = CurrentDateTimeProvider(); 


and IFlushEntityEventListener
public void OnFlushEntity(FlushEntityEvent @event) 

if(@event.EntityEntry.Status == Status.Deleted) 

return; 

var trackable = @event.Entity as ITrackModificationDate; 
if (trackable != null) 

trackable.LastModified = CurrentDateTimeProvider(); 


As you can see, using right events you don't need to use NH internals state.

For collection you have another set of events. In general you shouldn't initialize a collection in an NH's event.

2011/5/6 Krzysztof Koźmic <krzyszto...@gmail.com>

--
You received this message because you are subscribed to the Google Groups "nhusers" group.
To post to this group, send email to nhu...@googlegroups.com.
To unsubscribe from this group, send email to nhusers+u...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/nhusers?hl=en.




--
Fabio Maulo

Krzysztof Kozmic

unread,
May 7, 2011, 12:10:43 AM5/7/11
to nhusers
I did briefly try that, and ended up having some different issues
(don't remember exactly what the problem was now, I'll try to
reproduce that on Monday).

Does FlushEventListener get called for dirty objects only?

Cheers,
Krzysztof

On May 6, 10:04 pm, Fabio Maulo <fabioma...@gmail.com> wrote:
> IPreUpdate is intended to be used for entity-state checking (veto) not to
> change the state.
> What is happening is that NH found a strange operation in a collection
> (something like "somebody have changed it outside my control or I have a
> bug").
> For what you need you have to use ISaveOrUpdateEventListener
> public void OnSaveOrUpdate(SaveOrUpdateEvent @event)
> {
> var trackable = @event.Entity as ITrackModificationDate;
> if (trackable != null)
> {
> trackable.LastModified = CurrentDateTimeProvider();
>
> }
> }
>
> and IFlushEntityEventListener
> public void OnFlushEntity(FlushEntityEvent @event)
> {
> if(@event.EntityEntry.Status == Status.Deleted)
> {
> return;}
>
> var trackable = @event.Entity as ITrackModificationDate;
> if (trackable != null)
> {
> trackable.LastModified = CurrentDateTimeProvider();
>
> }
> }
>
> As you can see, using right events you don't need to use NH internals state.
>
> For collection you have another set of events. In general *you shouldn't
> initialize a collection* in an NH's event.
>
> 2011/5/6 Krzysztof Koźmic <krzysztof.koz...@gmail.com>

Krzysztof Kozmic

unread,
May 8, 2011, 9:29:15 PM5/8/11
to nhusers
ok here comes the update.

I checked the approach outlined by Fabio again. I implemented the
ISaveOrUpdate and IEntityFlush event listeners and I set the values
directly on the object.

However even though I can see the values are set on the object the
INSERT that NHibernate tries to execute passes NULL values for those
properties instead.

Also as a sidenote I noticed even non-dirty objects are passed to
those listeners which is at least surprising to me.

Also as another sidenote, I used as my base class
DefaultSaveOrUpdateListener and I'm overriding EntityIsPersistent/
EntityIsTransient methods and NHibernate is passing my newly created
object to EntityIsPersistent method which is again at least
surprising.

Anyway - the biggest issue is that NHibernate does not seem to care
about the values I provide to the object in the listener and I'm sure
they are set, because if I look in the debugger at the time the
exception is thrown the values are set and I could see my listeners
get hit.

cheers,
Krzysztof

On May 7, 2:10 pm, Krzysztof Kozmic <krzysztof.koz...@gmail.com>
wrote:
> > 2011/5/6 Krzysztof Ko¼mic <krzysztof.koz...@gmail.com>

José F. Romaniello

unread,
May 8, 2011, 9:53:48 PM5/8/11
to nhu...@googlegroups.com
1 use the interface as fabio Said.
2 the order of the listeners is important. I think you should put
yours after the nhibernates for this case... But to be honest i am not
sure. Ill try it tomorrow

2011/5/8, Krzysztof Kozmic <krzyszto...@gmail.com>:

--
Enviado desde mi dispositivo móvil

Ricardo Peres

unread,
May 9, 2011, 5:30:03 AM5/9/11
to nhusers
@Krzysztof:

Shouldn't you be calling the base class' implementation?

public class MySaveOrUpdateEventListener:
DefaultSaveOrUpdateEventListener
{
public override void OnSaveOrUpdate(SaveOrUpdateEvent @event)
{
//do something with the entity
base.OnSaveOrUpdate(@event);
}
}

On May 9, 2:53 am, José F. Romaniello <jfromanie...@gmail.com> wrote:
> 1 use the interface as fabio Said.
> 2 the order of the listeners is important. I think you should put
> yours after the nhibernates for this case... But to be honest i am not
> sure. Ill try it tomorrow
>
> 2011/5/8, Krzysztof Kozmic <krzysztof.koz...@gmail.com>:

Krzysztof Kozmic

unread,
May 10, 2011, 12:36:33 AM5/10/11
to nhusers
@Ricardo

I was. Actually I was overriding EntityIsTransient/Persistent methods
and calling return base.ThisMethod() at the end

Krzysztof

Scott Findlater

unread,
May 11, 2011, 8:41:30 AM5/11/11
to nhusers
@Krzysztof Have you managed to get a solution to this, I am in a
similar situation and attempting to get a conclusive answer
http://groups.google.com/group/nhusers/browse_thread/thread/b6807c2a486073d8/48a40348dbeb8799#48a40348dbeb8799

On May 10, 5:36 am, Krzysztof Kozmic <krzysztof.koz...@gmail.com>
wrote:

José F. Romaniello

unread,
May 11, 2011, 12:58:35 PM5/11/11
to nhu...@googlegroups.com
@Krzysztof
here (branch: with-user-audit) you have a full working example with Modified(date) and ModifiedBy.
Let me know how to break it so i can help you, works well for me so far.


2011/5/11 Scott Findlater <scottfi...@gmail.com>
Reply all
Reply to author
Forward
0 new messages