Robert,

All I can say is "wow", thanks for the insights.  This is especially important 
because you use both frameworks.

Please let me ask some more questions.  (Note: as I said, I was initially 
attracted to Cayenne because it had familiar design patterns to EOF, which I 
thought was fairly mature at the time, so I may not understand the 
Hibernate-way of "thinking").

RE ObjectContext vs Session
I may be mixed up but it sounds like the ObjectContext is similar in concept to 
EOF.  It sounds like you are saying that among other things the 
Hibernate-Session makes simple transactional tasks much more difficult and may 
even interfere with a Factory-Method approach to building data objects within a 
transaction.

RE Lazy Fetching
If I have the concept correct, this is another term for what EOF calls 
"faulting" behavior.  IMO optimized/smart faulting behavior is the single most 
important reason to use an ORM.  The conceptual differences between a RDBMS and 
an OO language can result in massive problems with a macro design, one that a 
good ORM solves via intelligent faulting algorithms. I had just assumed that 
this was a "moot" issue based on the fundamental solutions offered by EOF.  Are 
there any essential differences in features of "Lazy Fetching" that you can 
point out?

RE dbentity/objentity differences

Is the reason associated with the maturity of the "faulting" behavior (or 
something else)?

RE Google "hibernate lazyinitializationexception" to see what I mean.

OK, I googled it as you suggested, and found a few (what I call dissertations) 
on the subject that suggest that Hibernate does not have a cogent "faulting" 
design, and that the Hibernate-Session is not as mature a model for 
transactions as is Cayenne's ObjectContext (if I understand the issues).  Is 
this correct?

Correct me if I am wrong (please :) ), but it is starting to sound similar to 
the discussions of C++ garbage collection vs Java garbage collection (i.e. C++ 
doesn't really embrace garbage collection as a problem that should be handled 
by anyone but the programmer)

Thanks again for your input,
Joe






 







On Sep 6, 2010, at 11:06 AM, Robert Zeigler wrote:

> Hi Joe,
> 
> First, this e-mail wound up a lot longer than I intended, apologies! The 
> short version is: having used both a fair bit, I prefer cayenne, but they 
> both have strengths and weaknesses. Most of this e-mail details what I view 
> as weaknesses in Hibernate. :)
> 
> On to the long version! 
> 
> I still know cayenne better than hibernate, but I've used both extensively 
> (2+ years of experience with hibernate, on a fairly large system with > 80 
> tables; I've used cayenne for > 5 years now).  I don't have time right now to 
> put together a systematic comparison, but here are a few notes:
> 
> Hibernate: POJO - some people love it, some hate it. I'm in the latter camp.  
> You lose out on a lot of code-reuse, debugging is more difficult, and it 
> necessitates constructs like hibernate proxies, which are a PITA to deal 
> with, IMO.
> Cayenne: interface (inheritance, in practice)-based design.  Some people 
> don't like the domain-structure constraints it imposes.  I find it makes 
> debugging easier and results in more code re-use. And, no proxies.  Objects 
> are what they are.  More importantly, objects are what you think they are (in 
> hibernate-land, I've had code like the following:
> 
> public class MyObject2 extends MyObject1 {...}
> 
> elsewhere:
> 
> MyObject1 someobj = someCodeThatReturnsMyObject1();
> if (MyObject2.class.isInstance(someobj)) {
>  ((MyObject2)someobj).callMyObject2Method();
> }
> 
> And the above code will throw a cast class exception.  Yup.  That's right.  
> Because someobj is a proxy.  A call to getClass() returns the getClass() of 
> the underlying object (an instance of MyObject2), but someobj, the proxy, 
> technically only implements MyObject1.  So you get a ClassCastException.  
> Other variants include your code not executing at all, even when you know 
> that someobj /should/ be an instance of MyObject2. The code above is, of 
> course, contrived, but I've hit this in numerous "real world" scenarios.
> 
> Hibernate & Cayenne both support "lazy fetching" in some form, but Cayenne's 
> support is far superior, IMO (with bonafide faulting, etc.).  This is a 
> function, I think, of having supported it far longer (this was initially the 
> reason that I used Cayenne rather than Hibernate).  Google "hibernate 
> lazyinitializationexception" to see what I mean.  In particular, if you go 
> the hibernate route, be very /very/ careful what you do in event listeners 
> (pre/post commit, etc.) because it's very easy to hit exceptions there.  
> Basically, I find that in Hibernate, event listeners are just barely better 
> than useless.  A great idea, but you can't really /do/ anything useful in 
> them.  And even the 3rd party modules, written by long-time hibernate 
> developers, hit these edge cases (eg: hibernate envers for entity 
> auditing/logging has had issues reported where they hit issues with 
> lazyinitializationexception from using lifecycle listeners).  The hibernate 
> "way" was originally to not support lazy fetching at all; either all of the 
> data you needed came into the request/session at once, or it wasn't there at 
> all.  This probably resulted in more /performant/ code (fewer queriest/hits 
> to the db, for instance), but is basically not feasible in the world of 3rd 
> party modules/integration/development: it's not always possible to know 
> exactly what information you need at the beginning of, eg, a web request.
> 
> I have to give kudos to the hibernate team for the extremely flexible 
> mappings they support.  I find cayenne mapping more /intuitive/ (thanks in 
> part to the modeler), but there are edge mapping cases that are supported in 
> hibernate that are not, to the best of my knowledge, supported in cayenne 
> (cayenne 3.0 improves this discrepancy, though).  As an example, hibernate 
> supports more inheritance modeling schemes (table per concrete subclass, 
> table per class, single table) than does cayenne, although cayenne 3.0 has 
> improved in this regard.  For simple mapping, hibernate may even be more 
> straightforward than cayenne due to it's ability to analyze your domain 
> objects and figure out the appropriate tables, etc. to create.  On the other 
> hand, I personally shy away from having hibernate auto-create my table 
> structure.  I find it results in less thinking about what's really occurring 
> at the db level.  Although that is, to a greater or lesser extent, the point 
> of an ORM system, it's my opinion that it's still important to think about 
> how the data is physically mapped at the db level.  (I should note that you 
> can specify the exact mapping characteristics in hibernate.  But my 
> observation is that the tendency is to let hibernate "do it's thing" until 
> you find a problem with the way it did it's thing, and you tell hibernate the 
> "right way" to do it). 
> 
> Metadata: There's no "dbentity" vs. "objentity" separation.  That's great for 
> some people... but really too bad. :) My personal experience is that 
> cayenne's meta-data support is more accessible and richer than Hibernate's, 
> but that's probably a function, at least in part, of familiarity with the 
> frameworks.  
> 
> pks: Cayenne's approach is: "these are a database-artifact and shouldn't 
> pollute your data model, unless you need them to be there".  Hibernate's 
> approach is: "pk's are an integral part of your domain object" (for the most 
> part).
> 
> ObjectContext vs. Session.  Session is a poor man's ObjectContext. ;) That's 
> an opinion, of course.  But. On the surface, these two objects do similar 
> sorts of things: save, commit transactions, etc.  But in reality, they are 
> completely different paradigms.  In Cayenne, an ObjectContext is very much a 
> "sandbox" where you can make changes, roll them back, commit them, etc.  A 
> hibernate session is more like a command queue: you instruct it to update, 
> save, or delete specific objects, ask it for "Criteria" for criteria-based 
> queries, etc.  They may sound similar but there's a big difference in how you 
> use them.  Basically, hibernate doesn't have the notion of "modified or new 
> object that needs to be saved at some point in the future, but which I should 
> retain a reference to now." :) In cayenne, you can do something like this:
> 
> void someMethod(ObjectContext context) {
>   context.newObject(SomePersistentObject.class).setSomeProperty("foo");
>   ...
> }
> 
> Now when that particular context is committed, a new instance of 
> SomePersistentObject will be committed, without the calling code having to 
> know about it.  Arguably, this is a method witih "side effects" that should 
> be avoided, but there are legitimate use cases for this.  Consider a recent 
> example I encountered.  A hibernate project I work on manages a set of 
> "projects".  Changes to projects are audited, except when the project is 
> first created/in state "project_created" (a custom flag, unrelated to 
> hibernate).  I recently needed to add support for one auditing operation: 
> record the date of creation, and the user who created the project.  WIthout 
> getting into gory details, the simplest way to do this would have been to 
> modify the service responsible for creating all project types, along the 
> lines of this (how I would do this in cayenne):
> 
> public <T extends Project> T createProject(Class<T> type) {
>   T project = codeToCreateProject();
>   Audit a = objectContext.newObject(Audit.class);
>   a.setProject(project);
>   a.setMessage("Project Created");
>   a.setDate(new Date());
>   return project;
> }
> 
> Notes: the project creator is not (and cannot, due to design constraints) 
> commit the project to the database at this point in the code.  That's fine in 
> cayenne: as long as the calling code is using the same object context (it 
> always would be in my case), the Audit object would be committed at the same 
> time the project is, and life would be happy.  But the project is not 
> cayenne. It is hibernate.  So:
> 
> public <T extends Project> T createProject(Class<T> type) {
>   T project = codeToCreateProject();
>   Audit a = new Audit();
>   a.setProject(project);
>   a.setMessage("Project Created");
>   a.setDate(new Date());
>   return project;
> }
> 
> Except, what happens to a? The answer is: nothing.  It isn't ever saved.  It 
> would be, if Project had a reverse relationship to audit (List<Audit> 
> getAudits()), that was set to cascade the "save" and "update" operations.
> But Project didn't/doesn't, and I wasn't allowed to add it.  There was no way 
> to tell hibernate: "Look, I've got this object, and I wan't you to save it, 
> but, not right this second".  You can call: session.save(a).  But that 
> results in an immediate commit the audit object (and ONLY the audit object!), 
> so if the project isn't yet persisted to the db, you get a relationship 
> constraint violation, trying to save a relationship to an unsaved object.  
> There's also a session.persist(a) method, part of EJB3 spec, which is 
> theoretically like cayenne's "register", but in hibernate, its functionally 
> equivalent (or very nearly so) to session.save(a): it triggers an immediate 
> commit to the database (at least in our application setup).  There is no 
> equivalent to cayenne's "context.register(a)".  I finally solved this issue 
> via life cycle event listeners, and it was a pain (you have to be /extremely/ 
> careful about what you do in hibernate event listeners.  In particular, read 
> operations that result in a hit to the database will cause you major grief, 
> even if you don't modify anything, and modification of any kind is next to 
> impossible).  
> 
> All that said, there are /some/ good ideas in hibernate. :)  For one thing, 
> Cayenne's /requirement/ that two objects with a shared relationship be in the 
> same ObjectContext can cause grief, particularly in web applications.  
> Imagine you have a form to create a new object of type Foo.  Foo has a 
> relationship to Bar.  You may not want to register this object with the 
> context until you know that the new Foo object is a "valid" object (lest you 
> wind up with "dirty" objects polluting subsequent commits, using an 
> ObjectContext-per-user session paradigm).  But you can't do that: when you 
> set the Bar relationship, Foo will be registered with the context.  That's 
> usually fine... you can usually rollback the changes... but it does mean 
> sometimes having to think carefully about what "state" your objects are in.
> 
> I've yet to find the "perfect" ORM.  THere isn't one, as far as I'm 
> concerned, b/c there's simply a mismatch between the db model and the object 
> model that will result in tradeoffs.  But I find Cayenne far easier to learn 
> and use than Hibernate.
> 
> Cheers,
> 
> Robert
> 
> On Sep 5, 2010, at 9/51:21 PM , Joe Baldwin wrote:
> 
>> Hi,
>> 
>> I am again responsible for making a cogent Cayenne vs Hibernate Comparison.  
>> Before I "reinvent the wheel" so-to speak with a new evaluation, I would 
>> like to find out if anyone has done a recent and fair comparison/evaluation 
>> (and has published it).
>> 
>> When I initially performed my evaluation of the two, it seemed like a very 
>> easy decision.  While Hibernate had been widely adopted (and was on a number 
>> of job listings), it seemed like the core decision was made mostly because 
>> "everyone else was using it" (which I thought was a bit thin).
>> 
>> I base my decision on the fact that Cayenne (at the time) supported enough 
>> of the core ORM features that I needed, in addition to being very similar 
>> conceptually to NeXT EOF (which was the first stable Enterprise-ready ORM 
>> implementations).  Cayenne seems to support a more "agile" development 
>> model, while being as (or more) mature than EOF.  (In my opinion. :) )
>> 
>> It seem like there is an explosion of standards, which appear to be driven 
>> by "camps" of opinions on the best practices for accomplishing abstraction 
>> of persistence supporting both native apps and highly distributed SOA's.
>> 
>> My vote is obviously for Cayenne, but I would definitely like to update my 
>> understanding of the comparison.
>> 
>> Thanks,
>> Joe
>> 
> 

Reply via email to