-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 21 posts ]  Go to page 1, 2  Next
Author Message
 Post subject: Writing simple business logic into POJO .. why not work?
PostPosted: Tue Oct 03, 2006 2:42 pm 
Newbie

Joined: Tue Oct 03, 2006 2:07 am
Posts: 18
I read many books about hibernate but no one concern with writing business logic into POJO. Maybe it is absolutly clear(we firstly think it too), but we deeply stuck with it.

It will be nice to provide clear rules what DO and what DO NOT in Interceptor method. How POJO can be notificated than will be deleted. Rules if you can stop it. Rules if you can insert another POJO in notification method. etc .. If is preferable way do it with events or Interceptor interface. If you can use session in notification method, if you cant use find() and load() in this methods, etc..

Now I realize you cant use this methods in for example preFlush method to make some checks .. and this means for us Hibernate is unusable for us!!

We realy deeply stuck with it.. with hibernate many exotic exceptions.

One example follows :
We have master and slave tables. Slave have id_master column.
And all we need is when user in UI tier change id_master in slave table we want to reconect to another master.

@Entity
public class Slave {

private Integer id_master;
public void setId_master(Integer id_master){
this.id_master = id_master;

//non working busines logic
//we simply want switch to real master if id_master change

Code:
        if (id_master!=null && !id_master.equals(this.id_master)){
            master = (Master) getLocalHibernateTemplate().load(Master.class,id_master));
        }


}


@ManyToOne(cascade={},fetch=FetchType.LAZY)
@JoinColumns({
@JoinColumn(name="id_master", referencedColumnName="id_master", unique=false, nullable=false, insertable=false, updatable=false)
})
private Master master;
public Master getMaster() { return this.master; }
public void setMaster(Master master) {
//remove old
if (this.master != null) {
this.master.getSlaves().remove(this);
}
//add new
this.master = master;
if (this.master != null) {
this.master.getSlaves().add(this);
}
}
}


In http://www.hibernate.org/116.html#A25 I found simple statement from hibernate team this do not work :
Also, make sure that a call to an accessor method couldn't do anything wierd ... like initialize a lazy collection or proxy.

But how-to write this kind of code ?
Need help.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Oct 03, 2006 5:43 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 6:10 am
Posts: 8615
Location: Neuchatel, Switzerland (Danish)
There are clear rules what you can do and cannot do. (and i really don't get what Interceptor code has to do with business logic in your pojo ?)

The general rule is don't trigger/acess the session directly nor indirectly from inside an interceptor method nor accessors that you have told hibernate to use. That is it - nothing else.

so if you had read the faq entry you refers it gives you the solution - have alternative accessors. One of the possible alternatives is to use field access and hibernate won't go through your accessros to create the objects.

_________________
Max
Don't forget to rate


Top
 Profile  
 
 Post subject:
PostPosted: Wed Oct 04, 2006 5:25 am 
Newbie

Joined: Tue Oct 03, 2006 2:07 am
Posts: 18
max wrote:
There are clear rules what you can do and cannot do. (and i really don't get what Interceptor code has to do with business logic in your pojo ?).


We use method in Interceptor to callback POJOs. Maybe right way is use events or Lifecycle interface ? Realy dont know.

public class MyInterceptor extends EmptyInterceptor {

public void onDelete(Object entity, Serializable id, ...) throws CallbackException {
if(entity instanceof DODeletableAware) {((DODeletableAware)entity).onDelete();}
}

public void preFlush(java.util.Iterator entitiesToFlush) throws CallbackException {
...
if (obj instanceof DOPreFlushAware) {((DOPreFlushAware) obj).onPreFlush();}
}

}

And this method do additional checks. Load and save another entities. Can say some business logic. Right?
But if this way is wrong how to write this right?
(Just now we cant use JSR-220 @Pre... and @Post.. annotations)


max wrote:
The general rule is don't trigger/acess the session directly nor indirectly from inside an interceptor method nor accessors that you have told hibernate to use. That is it - nothing else.


So how to write preFlush(preCommit) check on Slave that read Master values and maybe insert to another table. I must have accessible session to do that.
In events method can I use session to find and save objects ?

max wrote:
so if you had read the faq entry you refers it gives you the solution - have alternative accessors. One of the possible alternatives is to use field access and hibernate won't go through your accessros to create the objects.


This I realy dont get it. What is it mean "have alternative accessors".
And what is the purpose of this.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Oct 09, 2006 12:30 pm 
Newbie

Joined: Tue Oct 03, 2006 2:07 am
Posts: 18
Solution is explained at http://www.hibernate.org/156.html

Still missing in hibernate doc what methods deny use session and what allow session manipulation. Interceptor and Events interface method should be described.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Oct 09, 2006 3:00 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 6:10 am
Posts: 8615
Location: Neuchatel, Switzerland (Danish)
there is no description needed since it is *all* methods that dissallow access to the session - pure and simple.

_________________
Max
Don't forget to rate


Top
 Profile  
 
 Post subject:
PostPosted: Tue Oct 10, 2006 9:06 am 
Newbie

Joined: Tue Oct 03, 2006 2:07 am
Posts: 18
max wrote:
there is no description needed since it is *all* methods that dissallow access to the session - pure and simple.



This is not true!

Interceptor.postFlush() allow session manipulation (as described in link above).

And when I looked into source code into "event" system I surely find few next methods allow session manipulating.


Anyway Interceptor.postFlush() is only chance to make complex validation and only reason we dont delete all hibernate JARs from our disks !!


Make only "Anemic Domain Model" data-holder with no logic is for losers ...


Top
 Profile  
 
 Post subject:
PostPosted: Tue Oct 10, 2006 9:19 am 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 6:10 am
Posts: 8615
Location: Neuchatel, Switzerland (Danish)
You are referring to a community written page; not official hibernate documentation.

The reason postFlush() works is that it is called as the last step in session work. Using the session there is not very good since it will trigger more loads/making things dirty which will not be part of the flush....eventually resulting in data not being persisted to the db.

And I have no clue why you say you have to write anemic models....you just need to tell hibernate to not use your property accessors and use field access instead. Then you can do whatever you want.

There is probably parts of the event system that allows using the session; but there is no easy answer since it all depends on the flow of your app and the things you want to do.

I have seen tons of rich domain models that works fine with hibernate and especially also models that works without hibernate (e.g. for unit testing) ...they didn't have any issues since they added validation to the upper layers.

_________________
Max
Don't forget to rate


Top
 Profile  
 
 Post subject:
PostPosted: Tue Oct 10, 2006 12:18 pm 
Newbie

Joined: Tue Oct 03, 2006 2:07 am
Posts: 18
Then I still missing something..

We already use field access for hibernate and accessors method for us.

@Id
private Integer id_pr;
public Integer getId_pr() { return id_pr; }
public void setId_pr(Integer id_pr) {
this.id_pr = id_pr;
}

We dont use public properties because encaptulation business logic on set method
and MAINLY because when class is lazy loaded by CGLIB it has all fields null when direct accessing property. We must call get method to get real value.


Anyway how you write this code without postFlush() :

@Id
private Integer id_pr;
public Integer getId_pr() { return id_pr; }
public void setId_pr(Integer id_pr) {

//simple check
if (id_pr<0) {
session.save(new LoggingTable("warning: weird id") );
}

//or check on master - maybe init proxy so error
if (master.getNegativeSlavesAllowed()){
...
}

this.id_pr = id_pr;
}

I think you cant :-) Show yourself !


I cant imaginate "tons of rich domain models" that cannot perform even simple checks as above.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Oct 10, 2006 12:30 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 6:10 am
Posts: 8615
Location: Neuchatel, Switzerland (Danish)
if you use field access for your id there is no problem with the code you showed me (besides having direct session access in your domain model)

_________________
Max
Don't forget to rate


Top
 Profile  
 
 Post subject:
PostPosted: Tue Oct 10, 2006 12:44 pm 
Newbie

Joined: Tue Oct 03, 2006 2:07 am
Posts: 18
max wrote:
if you use field access for your id there is no problem with the code you showed me



If I use pure field access without set and get method :

@Id
public Integer id_pr;

where I write business logic ???




max wrote:
besides having direct session access in your domain model


But we need session access ! How to do that ???


Top
 Profile  
 
 Post subject:
PostPosted: Tue Oct 10, 2006 12:47 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 6:10 am
Posts: 8615
Location: Neuchatel, Switzerland (Danish)
you don't need it to be public!

And why do you want to apply business logic when hibernate loads data from the db and assign values to your beans ? (and vice versa when it needs to read data ?)

you can still have your getter and setters.

_________________
Max
Don't forget to rate


Top
 Profile  
 
 Post subject:
PostPosted: Tue Oct 10, 2006 12:48 pm 
Newbie

Joined: Tue Oct 03, 2006 2:07 am
Posts: 18
How about JSR-220 and @PostPersist method. Is there allowed entity manager access in the standard ?


Top
 Profile  
 
 Post subject:
PostPosted: Tue Oct 10, 2006 12:57 pm 
Newbie

Joined: Tue Oct 03, 2006 2:07 am
Posts: 18
max wrote:
you don't need it to be public!

And why do you want to apply business logic when hibernate loads data from the db and assign values to your beans ? (and vice versa when it needs to read data ?)

you can still have your getter and setters.



I dont want trigger business logic when hibernate loads or save data. I have field access on in hibernate config.There is no problem.

I want trigger business logic when on application server somebody call setID() on object. Then I need make complex validation that involve use session on possibly uninitialized master proxy.


I still think this is pretty common need. I am suprised there not clear way how to do it.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Oct 10, 2006 1:01 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 6:10 am
Posts: 8615
Location: Neuchatel, Switzerland (Danish)
so if you are fine with having direct session/db access in the pojo's why don't you just do it then ?

_________________
Max
Don't forget to rate


Top
 Profile  
 
 Post subject:
PostPosted: Tue Oct 10, 2006 1:09 pm 
Newbie

Joined: Tue Oct 03, 2006 2:07 am
Posts: 18
One more time :

@Id
private Integer id_pr;
public Integer getId_pr() { return id_pr; }
public void setId_pr(Integer id_pr) {

if (master.getNegativeSlavesAllowed()){
...
}

this.id_pr = id_pr;
}

This is clear hibernate .. no direct session or DB access. But it ends with exception when "this" and "master" object is both uninitialized proxy.

I want use hibernate .. but cant! Even in this simples check!!


Must use Interceptor postFlush and callback method to this bean to do this check after session is flushed potentialy rollback or add some more bean to dirty list.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 21 posts ]  Go to page 1, 2  Next

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.