FAQ
Well of course your answer will be Yes :-)
So, more specifically, I'm interested in hearing about the relative strengths and weaknesses of sessionless ORMs, e.g. Ebean.

I'd like to hear opinion, trench stories, and such.

Here's some things I that may or may not be relevant, any feedback welcome:

1. I'm in a J2SE project. There are wishes to convert that into J2EE, or at least partition the J2SE app into a J2EE-compatible service layer and a GUI. (There is also a nightly batch app that I don't see ever arriving in J2EE land. No use case for that.)

2. I can't take any risks. The project is in bad standing already because of all the time (more than a person-year) sunk into identifying and solving Hibernate hassles; another delay on that order of magnitude and I'm out of my current job. I can probably convince my higher-ups to sink another person-month into getting away from Hibernate, but I need to give solid guarantees.
So: any feedback from people who have done that kind of transition would be very, very much appreciated, with a particular emphasis on traps to avoid.

3. I have no LOBs, no wide tables, and all bulk data goes over gigabit ethernet so I don't need no fieldwise laziness.
However, I have no experience with a framework that does not use bytecode generation, so I'm curious how the differences turn out in practice.
So... what do people think about pros and cons of runtime bytecode generation?

4. I'd like to ensure stuff like "Order.totalValue needs to be the sum of all associated OrderDetail.value fields".
"Interesting" aspects here:
- Other applications might have modified OrderDetail records during user think time. I'd prefer the ORM simply updating the totalValue to whatever is in the database over getting a concurrent modification complaint (unless the current app loaded the same OrderDetail and changed the value field to something different).
- The totalValue should get the correct value regardless of whether all pertinent OrderDetails were loaded. (This probably means running an UPDATE statement with SUM(value) in during flush/commit.)
- Various permutation about which fields in Order were modified by the current and the other application, and doing the Right Thing in each case (too much detail for a single post so I'm leaving that out for now).
BTW Hibernate doesn't do this, so supporting that use case would allow me to argue that we're not only getting rid of problems but actually getting something better than initially asked for :-)

5. Those nested transactions (savepoints) are pretty cool and would be a major advantage. Sometimes we do have a series of steps and need to roll back some but not all of them (the "wizard situation").
Are there caveats in that area, or can I go ahead and use that as a selling point without worrying about having to go back on that later?

6. How much manual work is involved in reverse engineering?
For Hibernate, I found that the tool is only marginally better than simply specifying everything by hand. Maybe automatic reverse engineering generally isn't worth the hassle; after all, the tool only sees a VARCHAR(1) but cannot know whether it's just a boolean in disguise or a one-character status code, let alone guess the actual mapping between database strings and Java enum values. (We have lots of such things in our tables.)

Regards,
Jo

Search Discussions

  • Joe Baldwin at Aug 12, 2011 at 3:38 pm
    In My Opinion:

    - the EOF-like conceptual model of Cayenne & Cayenne Modeler was important to me
    - the OTB Cayenne memory management is excellent
    - the Cayenne "faulting" behavior is advanced (and leaves one wondering why anyone would choose Hibernate - I think one could call Hibernate faulting-behavior "non existent" if one were to explore this issue in detail)
    - Cayenne Modeler tool is professional quality and supports reverse engineering as well as an evolving design methodology
    - the only "advantage" of Hibernate that I have been able to discern is that it is currently "conventional wisdom" among a certain class of project managers who's evaluation process appears to be to evaluate solely based on "conventional wisdom" and then call it a day. I find the "conventional wisdom" evaluation process to be flawed.

    Joe



    On Aug 12, 2011, at 10:36 AM, Durchholz, Joachim wrote:

    Well of course your answer will be Yes :-)
    So, more specifically, I'm interested in hearing about the relative strengths and weaknesses of sessionless ORMs, e.g. Ebean.

    I'd like to hear opinion, trench stories, and such.

    Here's some things I that may or may not be relevant, any feedback welcome:

    1. I'm in a J2SE project. There are wishes to convert that into J2EE, or at least partition the J2SE app into a J2EE-compatible service layer and a GUI. (There is also a nightly batch app that I don't see ever arriving in J2EE land. No use case for that.)

    2. I can't take any risks. The project is in bad standing already because of all the time (more than a person-year) sunk into identifying and solving Hibernate hassles; another delay on that order of magnitude and I'm out of my current job. I can probably convince my higher-ups to sink another person-month into getting away from Hibernate, but I need to give solid guarantees.
    So: any feedback from people who have done that kind of transition would be very, very much appreciated, with a particular emphasis on traps to avoid.

    3. I have no LOBs, no wide tables, and all bulk data goes over gigabit ethernet so I don't need no fieldwise laziness.
    However, I have no experience with a framework that does not use bytecode generation, so I'm curious how the differences turn out in practice.
    So... what do people think about pros and cons of runtime bytecode generation?

    4. I'd like to ensure stuff like "Order.totalValue needs to be the sum of all associated OrderDetail.value fields".
    "Interesting" aspects here:
    - Other applications might have modified OrderDetail records during user think time. I'd prefer the ORM simply updating the totalValue to whatever is in the database over getting a concurrent modification complaint (unless the current app loaded the same OrderDetail and changed the value field to something different).
    - The totalValue should get the correct value regardless of whether all pertinent OrderDetails were loaded. (This probably means running an UPDATE statement with SUM(value) in during flush/commit.)
    - Various permutation about which fields in Order were modified by the current and the other application, and doing the Right Thing in each case (too much detail for a single post so I'm leaving that out for now).
    BTW Hibernate doesn't do this, so supporting that use case would allow me to argue that we're not only getting rid of problems but actually getting something better than initially asked for :-)

    5. Those nested transactions (savepoints) are pretty cool and would be a major advantage. Sometimes we do have a series of steps and need to roll back some but not all of them (the "wizard situation").
    Are there caveats in that area, or can I go ahead and use that as a selling point without worrying about having to go back on that later?

    6. How much manual work is involved in reverse engineering?
    For Hibernate, I found that the tool is only marginally better than simply specifying everything by hand. Maybe automatic reverse engineering generally isn't worth the hassle; after all, the tool only sees a VARCHAR(1) but cannot know whether it's just a boolean in disguise or a one-character status code, let alone guess the actual mapping between database strings and Java enum values. (We have lots of such things in our tables.)

    Regards,
    Jo
  • Robert Zeigler at Aug 12, 2011 at 5:30 pm
    For the last 3 or so years, I've been using hibernate more-or-less day-to-day. Not by choice, per se, but because I've been working on a project that used it. This is my experience, some of which may stem from lack of knowledge of hibernate, but:

    1) Personally, I find the "mental model" behind Cayenne easier to follow/understand. An object context is a sandbox. You make your changes and commit them. WIth hibernate, you have a session that's kinda similar, but still not the same. There's more-or-less no notion of "detached" objects in Cayenne (there are transient objects, but it's not the same). A hibernate session is much more closely tied to a transaction than Cayenne's ObjectContext (unless, maybe, you use Hibernate's session-per-user-session paradigm, which is generally discouraged).

    2) As Joe mentioned, there's faulting. There are certainly things you /can't/ do in hibernate. There is no (clean) way to have a lazy, non-mandatory toOne relationship. The only relationships that can be lazily fetched are mandatory toOne, and toMany. See, eg, here: http://community.jboss.org/wiki/SomeExplanationsOnLazyLoadingone-to-one for some suggested workarounds. Hibernate's lazy fetching model really feels like an afterthought. In fact, a number of years ago, hibernate really didn't support lazy fetching at all (at least not well) and one of the devs basically said that he thought lazy fetching was a bad idea; an application should know at the beginning of the request what data it needs and fetch it all in one swoop. Certainly, that's a nice idea in theory... but what if you're not running a webapp? There are other use-cases, even in a webapp, that make it extremely naive/wishful thinking. I wish I could find the thread now, but it was one of the espoused philosophies that originally turned me off to hibernate and on to Cayenne. You can see the sentiment/resistance to lazy loading here, though: https://forum.hibernate.org/viewtopic.php?t=930457&highlight=remote+lazy+loading, albeit for remote lazy loading. But the ideas espoused there are essentially the ones that were espoused earlier, on the web tier. Hibernate does have lazy loading now, but I still find it... finicky. It's way too easy to hit LazyInitializationException.

    3) POJO vs. inheritance
    Cayenne uses inheritance. Technically, it uses interfaces. Your objects must implement DataObject. In theory, you can do that without inheritance. In practice, that's fighting against the framework, and your objects will inherit from, say, CayenneDataObject (there's a client version, as well, for ROP). For some people, that's a real turn-off. They like their "POJO"s. The thing is... hibernate still uses inheritance. It's just inverted. They created an instrumented class that is a subclass of your class, and all access of your class goes through the subclass. It's an interesting solution, but not without it's pain points. I find hibernate applications MUCH harder to debug than Cayenne applications, precisely because you're dealing with a proxy. And, in fact, inspecting that proxy in a debugger can trigger database access that changes the path of execution. I was debugging an application that was hitting an exception (NPE or else LazyInitializationException, or something similar). Whenever I would try to debug it, the exception wouldn't appear. When I didn't, the exception would appear. I finally realized it was because I was inspecting the object earlier on, forcing a fetch of the associated values, resulting in a fully inflated object at the normal time of the exception. Oh what fun it was to debug that problem! As for runtime bytecode generation, I've seen it used well, and not. The critical thing is to have really good exceptions if your framework is going to use bytecode generation, because debugging generated bytecode is a pain. Unfortunately, Hibernate exceptions suck. :)

    Another issue occurs with the handling of inheritance. Suppose you fetch a list of SuperClass that has SubclassA and SubclassB. Depending on how you fetch SuperClass, the proxy will ONLY implement the SuperClass, so none of the objects will be instances of SubclassA or SubclassB. Ok, fine, you fetched SuperClass. Except... if you do something like:

    obj.getClass().getName(); => "SubclassA"
    or
    obj.getClass().isInstance(SubclassA.class); => true
    but
    SubclassA obj = (SubclassA) obj: //ClassCastException.

    This is because the proxy is only an instance of SuperClass, but the /delegate/ it wraps is a SubclassA (or B). And the calls to getClass() are passed on to the proxy. So in pretty much any way you can check for the class type, you'll be fooled into thinking you have a subclass instance, but you can't cast the object directly as a subclass. There are ways around this... but it's stupid that you have to work around it in the first place. I find Cayenne's "traditional" inheritance MUCH simpler to deal with, with fewer quirks. Also note that you can still insert your own custom superclass into the chain:

    MyClass extends MySuperClass{}
    MySuperClass extends CayenneDataObject{}

    Is perfectly legit.

    4) runtime metadata. You can get the metadata (mapping info) for entities in hibernate and in cayenne, but it's messed up in hibernate. :) Seriously, in my experience, it's MUCH easier to work with object metadata in Cayenne than in hibernate. It's one of the advantages of inheriting from CayenneDataObject. The information is all self-contained, so you can very easily access information such as database-level constraints. The integration library for cayenne and tapestry leverages this to automatically make fields required that are flagged as "not null" at the database level, and to constrain the length of input fields when using limited-width columns. This information /is/ available in Hibernate, but it's harder to get at, and the API for using it is extremely awkward. At least compared to Cayenne! :)

    Those are a few of the pain points I've experienced with Hibernate. That said, it does have some strengths.

    1) I do (kind of) like the annotation-based approach that is now available in hibernate. Not enough to abandon Cayenne + Cayenne Modeler, but if you like having all of the modeling info directly in your source (some do, some don't), or you like building your object and annotating on the fly, then this is nice. Hibernate provides fairly sane defaults for most things, so it means you build your class and annotate the deviances rather than having to annotate everything.

    2) Hibernate's implementation of inheritance is (probably) more complete than Cayenne's (I'm not sure where the current state is for Cayenne). So if you have really complex inheritance requirements, that's something to consider. Cayenne readily supports "single table inheritance" (there are other names). Cayenne also supports vertical/"joined table inheritance", where you have one table for the superclass, and then a table for each subclass. Cayenne currently doesn't support "horizontal" inheritance (no table for the superclass; one table for each concrete subclass); hibernate does. If you need that, you'll have to stick with hibernate (my condolences :).

    3) There are relative strengths and weaknesses to Cayenne's SelectQuery API vs. Hibernate's Criteria API. One of the really nice things in the Hibernate API is projections, which aren't quite as straightforward in Cayenne. The flip is is raw SQL. I find Cayenne's raw sql support, in the form of SQLTemplate, superior to Hibernate's sql execution. You can do it in Hibernate, but it feels dirty, whereas Cayenne more readily embraces the idea that not every query should be generated by the ORM. In fact, I've often considered forking Cayenne and creating a very small library that basically consists solely of SQLTemplate and DataRows. For small projects, having a simple way to externalize and centrally manage queries without introducing additional complexity would be great. :)


    In regards to your questions, specifically:

    1) Should be able to use Cayenne either way
    2) Starting with a new technology is always a risk, but generally, I think your risk is reasonably low with Cayenne. If you're beating your head against the wall with Hibernate, you'll probably find Cayenne's "mental model" more to your liking. As far as transitioning the project... I would probably start a new branch, reverse engineer the model from the database, tweak whatever properties need tweaking (you'll need to override the enum stuff, for instance, but that's pretty straightforward). Then generate your classes and migrate any custom code from the hibernate entities to the cayenne ones. Then delete the hibernate entities. :) You'll want to generate the cayenne entities in a different package than the Hibernate ones, at least initially. Once you nix the hibernate entities, you can bulk-move the Cayenne ones. As for specific pitfalls, without knowing more details about your project, it's hard to say. Are you required to audit entities? You're probably going to need to do that differently in Cayenne than in Hibernate (although I think listeners are friendlier in Cayenne than in Hibernate!)

    3) I addressed bytecode generation above. Basically, I prefer Cayenne's approach.

    4) ... maybe this is just me, but, I /usually/ try to avoid storing data that can be calculated. Sometimes it's justified, if the calculation is expensive, but unlikely to change frequently (eg: I've stored metadata about files in the db before so that the metadata was available without having to access the files). So in the case of the "totalValue", I would probably do that either as EJBQLQuery (I think it supports SUM?) or else as a SQLTemplate query. With the right query cache strategy, it should be performant. Then you don't worry about updating the value directly (you'll just have to know when to invalidate the cached query... which is when OrderDetail.value is modified or new OrderDetail is called) and cayenne can re-run the query for you, but will otherwise return the cached value. Then implement it in the object layer as a psuedo-property. Maybe other people have other solutions that are better, but that's what I'd do.

    5) They aren't nested transactions; they are nested contexts. And they can be very useful for aggregating a group of related changes together and isolating them from other changes in the context so you can throw them away as a group without worrying about losing your other changes. Very handy for dealing with dirty data!

    6) I would definitely start by reverse engineering the schema. You'll get all of the DbEntities created for you for free; they will usually be correct, as long as you've correctly supplied foreign key constraints, etc. You'll get the "Object Entities" as well, although you'll have to tweak those a bit to handle the enums. But reverse engineering should definitely save you time.

    Robert
    On Aug 12, 2011, at 8/1210:37 AM , Joe Baldwin wrote:

    In My Opinion:

    - the EOF-like conceptual model of Cayenne & Cayenne Modeler was important to me
    - the OTB Cayenne memory management is excellent
    - the Cayenne "faulting" behavior is advanced (and leaves one wondering why anyone would choose Hibernate - I think one could call Hibernate faulting-behavior "non existent" if one were to explore this issue in detail)
    - Cayenne Modeler tool is professional quality and supports reverse engineering as well as an evolving design methodology
    - the only "advantage" of Hibernate that I have been able to discern is that it is currently "conventional wisdom" among a certain class of project managers who's evaluation process appears to be to evaluate solely based on "conventional wisdom" and then call it a day. I find the "conventional wisdom" evaluation process to be flawed.

    Joe



    On Aug 12, 2011, at 10:36 AM, Durchholz, Joachim wrote:

    Well of course your answer will be Yes :-)
    So, more specifically, I'm interested in hearing about the relative strengths and weaknesses of sessionless ORMs, e.g. Ebean.

    I'd like to hear opinion, trench stories, and such.

    Here's some things I that may or may not be relevant, any feedback welcome:

    1. I'm in a J2SE project. There are wishes to convert that into J2EE, or at least partition the J2SE app into a J2EE-compatible service layer and a GUI. (There is also a nightly batch app that I don't see ever arriving in J2EE land. No use case for that.)

    2. I can't take any risks. The project is in bad standing already because of all the time (more than a person-year) sunk into identifying and solving Hibernate hassles; another delay on that order of magnitude and I'm out of my current job. I can probably convince my higher-ups to sink another person-month into getting away from Hibernate, but I need to give solid guarantees.
    So: any feedback from people who have done that kind of transition would be very, very much appreciated, with a particular emphasis on traps to avoid.

    3. I have no LOBs, no wide tables, and all bulk data goes over gigabit ethernet so I don't need no fieldwise laziness.
    However, I have no experience with a framework that does not use bytecode generation, so I'm curious how the differences turn out in practice.
    So... what do people think about pros and cons of runtime bytecode generation?

    4. I'd like to ensure stuff like "Order.totalValue needs to be the sum of all associated OrderDetail.value fields".
    "Interesting" aspects here:
    - Other applications might have modified OrderDetail records during user think time. I'd prefer the ORM simply updating the totalValue to whatever is in the database over getting a concurrent modification complaint (unless the current app loaded the same OrderDetail and changed the value field to something different).
    - The totalValue should get the correct value regardless of whether all pertinent OrderDetails were loaded. (This probably means running an UPDATE statement with SUM(value) in during flush/commit.)
    - Various permutation about which fields in Order were modified by the current and the other application, and doing the Right Thing in each case (too much detail for a single post so I'm leaving that out for now).
    BTW Hibernate doesn't do this, so supporting that use case would allow me to argue that we're not only getting rid of problems but actually getting something better than initially asked for :-)

    5. Those nested transactions (savepoints) are pretty cool and would be a major advantage. Sometimes we do have a series of steps and need to roll back some but not all of them (the "wizard situation").
    Are there caveats in that area, or can I go ahead and use that as a selling point without worrying about having to go back on that later?

    6. How much manual work is involved in reverse engineering?
    For Hibernate, I found that the tool is only marginally better than simply specifying everything by hand. Maybe automatic reverse engineering generally isn't worth the hassle; after all, the tool only sees a VARCHAR(1) but cannot know whether it's just a boolean in disguise or a one-character status code, let alone guess the actual mapping between database strings and Java enum values. (We have lots of such things in our tables.)

    Regards,
    Jo
  • Durchholz, Joachim at Aug 15, 2011 at 9:18 am
    Thanks to you and Christian, it has been very helpful. I'll wait the answers on Ebeans out and decide then :-)

    A few thoughts wrapping stuff up:
    There is no (clean) way to have a lazy, non-mandatory toOne relationship.
    Ah. An interesting snag that I haven't hit yet.
    Seems to be a quite rare case though. Making a to-one association eager usually isn't a performance problem. Unless you're in a situation where you need per-column laziness, too, but at least in my case, that's not a real issue. (The database server keeps 70% of the total database in RAM anyway...)
    one of the devs basically said that he thought lazy fetching was a bad idea;
    an application should know at the beginning of the request what data it
    needs and fetch it all in one swoop.
    Well, he's ignoring important use cases.
    Besides, I don't see the point; if you have a way to reattach objects, you have thrown transactional integrity out of the window anyway.

    What's needed is a way to verify integrity on writeback time. I.e. declaratively identify all the dependencies between data, and on commit, let the framework check that modified fields don't depend on fields that were concurrently modified.
    Hibernate does have lazy loading now, but I still find it... finicky.
    It's way too easy to hit LazyInitializationException.
    In my eyes, it's combining the disadvantages of strict discipline with the disadvantages of missing transactional integrity.

    Hibernate doesn't seem to be very clear about concepts in general. The whole codebase has an "additive" feel - like lots of interfaces heaped on top of each other, and each new feature written anew
    4) runtime metadata. You can get the metadata (mapping info) for
    entities in hibernate and in cayenne, but it's messed up in hibernate. :)
    Heh. Been there, done that.
    It *is* possible, and I got all the info that I needed. The awkwardness is because Hibernate offers the info at the database layer, and you need to know how that translates back up to the POJO level. Once you got that, it's all pretty straightforward though.

    One caveat: I'd have to reengineer things a bit if I ever get into the situation where multiple database fields map to a single Java property. It would be doable but I'd have to make a whole lot of my own code understand multiple-field attributes, so I have left that as an exercise to the reader :D
    1) I do (kind of) like the annotation-based approach that is now
    available in hibernate.
    Yes, those annotations are cool.
    Unfortunately, they didn't cover everything that the .hbm.xml mechanism covers, so I went back to .hbm.xml (with gritted teeth).
    I understand that annotations are moving along, so this may be different today than it was 18 months ago.
    Not enough to abandon Cayenne + Cayenne Modeler, but if you like having
    all of the modeling info directly in your source (some do, some don't),
    or you like building your object and annotating on the fly, then this is nice.
    I do.
    But... well... it didn't work very well in Hibernate anyway.
    And if it's the database that leads, you're tied to Hibernate's reverse engineering process, which distributes a lot of relevant semantic information into a single monolithic configuration file. Which plain sucks if you want the table-specific configuration in one place.

    I guess Cayenne can't do worse than that :-)
    2) Hibernate's implementation of inheritance is (probably) more complete
    than Cayenne's
    An interesting point, but not for my current project. We're doing oldschool DB design here, and inheritance doesn't really exist (except in the form of joined tables).
    Cayenne also supports vertical/"joined table inheritance", where you have
    one table for the superclass, and then a table for each subclass.
    That's good enough for us.
    After all, the database must be usable for ad-hoc SQL queries; fancy subclassing schemes don't work too well with that.
    Cayenne currently doesn't support "horizontal" inheritance (no table for the
    superclass; one table for each concrete subclass); hibernate does. If you
    need that, you'll have to stick with hibernate (my condolences :).
    You can always code around that. Use static functions for the common functionality across the tables.
    You don't get the encapsulation, but you do get the refactoring. (If people do ad-hoc queries, you're in unencapsulated land anyway, so you had that loss already.)
    2) Starting with a new technology is always a risk, but generally, I think
    your risk is reasonably low with Cayenne. If you're beating your head against
    the wall with Hibernate,
    I am, else I wouldn't be looking into alternatives. Switching horses in mid-races is the worst thing you can do, unless you are already banging your head against a stone wall.
    4) ... maybe this is just me, but, I /usually/ try to avoid storing data
    that can be calculated. Sometimes it's justified, if the calculation is expensive,
    Heh. I'm 100% with you on that.

    The issue is: people are scrolling through lists of orders. Many orders have a five-digit number of positions. I can't have the DB calculate that on the fly - not if they're doing a quick review over the last month's worth or orders, which would mean hundred thousands or millions of rows that go into the sums to be shown.

    The only way out that I really see is Oracle's "materialized views". But we want to be portable, at least in principle, and materialized views aren't in any standard yet.
    With the right query cache strategy, it should be performant.
    Well, the data changes rarely if ever. (I wouldn't be considering storing a sum field in the Order table otherwise.)
    I still am worried about performance.

    Plus there's the other problem: People want to see the sums in ad-hoc SQL, so I'm pretty much stuck with storing the sum in a table. (I could place it in a view, of course. Potentially making it slow, plus query users will have to remember to use the view for SELECT and the table for UPDATE.)
    5) They aren't nested transactions; they are nested contexts.
    Sorry, I was being sloppy with wording. I was thinking entirely from the perspective of code that does data modifications, in which case the only relevant property of DB transations is rollback, which is shared by contexts (as far as I understand contexts).

    My guess is that contexts share the rollback semantics of nested transactions. They certainly don't share the commit semantics, they'd fail with that on Persistence alone.

    Regards,
    Jo
  • Christian Grobmeier at Aug 12, 2011 at 4:56 pm
    Hello Joachim,

    first a little bit of shameless selfpromotion: in one of the next
    JavaMagazins you can read an article on Cayenne which shows up some
    differences to Hibernate. Anyway it might be to long for you. My
    background, I have used JDO before ages, was forced to use Toplink for
    a while and then migrated to Hibernate with which I worked for a long
    time. Early this year I decided to give Cayenne a try and was so
    impressed that I build my app upon it.

    I love the ease of use; I love that I didn't have to think on
    LazyInitializationExcpetions (not for you if you are in the SE world)
    and I love that I don't have to deal with proxies, which sometimes is
    a pain (to debug). And the modeler is one of the most helpful tools
    out there. I was used to configure everything by hand in Hibernate
    world and thought I would never use a tool like the modeler. But the
    modeler has the same priority in Cayenne world as the rest of the
    framework, so it is as excellent as the rest. I never felt the need to
    look into the xml configuration of Cayenne.
    1. I'm in a J2SE project. There are wishes to convert that into J2EE, or at least partition the J2SE app into a J2EE-compatible service layer and a GUI. (There is also a nightly batch app that I don't see ever arriving in J2EE land. No use case for that.)
    If it is a webapp you are planning (like me) you probably need to deal
    with LazyInit..Ex as mentioned above. I felt this is all easier to
    understand with Cayenne.
    2. I can't take any risks. The project is in bad standing already because of all the time (more than a person-year) sunk into identifying and solving Hibernate hassles; another delay on that order of magnitude and I'm out of my current job. I can probably convince my higher-ups to sink another person-month into getting away from Hibernate, but I need to give solid guarantees.
    Hibernate is able to solve edge cases of mappings. It is a real pain
    there, but you can do every ugly code you can imagine. If you have
    usual tables with relations and such, Cayenne is able to do all that
    very well. In fact you simply need to define your table in the
    modeler, choose your relations and the Java classes and everything is
    already created for you. You can even create queries in the modeler.
    All of that is very easy.

    I have had some trouble with Hibernate mappings myself when they were
    even pretty easy. I never felt such pain with Cayenne. There is some
    stuff you need to learn of course, but I have made the experience that
    the committers on this project are really nice and helpful. Even
    "stupid" questions are answered in pretty quick time. You can do a
    short lookup in the mail archives to prove that.

    Now, after my project is shortly before go live, I felt that Cayenne
    was the right choice for me. It was very straightforward for me to
    learn and to use. Learning curve is pretty low.
    3. I have no LOBs, no wide tables, and all bulk data goes over gigabit ethernet so I don't need no fieldwise laziness.
    However, I have no experience with a framework that does not use bytecode generation, so I'm curious how the differences turn out in practice.
    So... what do people think about pros and cons of runtime bytecode generation?
    I did never really trust it. In todays world it is used widely but I
    still do not trust it. I find it harder to debug. If you try look into
    a persistent bag of hibernate, a db call is being made. Not really a
    problem, but sometimes confusing. I have had many young people on my
    projects starting with Hibernate after their university. They all were
    puzzled on bytecode enhancement and I had tons to explain. Anyway, it
    is somehow standard, but I still don't like it. I like more the "what
    you code is what you get" way of live.
    4. I'd like to ensure stuff like "Order.totalValue needs to be the sum of all associated OrderDetail.value fields".
    "Interesting" aspects here:
    - Other applications might have modified OrderDetail records during user think time. I'd prefer the ORM simply updating the totalValue to whatever is in the database over getting a concurrent modification complaint (unless the current app loaded the same OrderDetail and changed the value field to something different).
    - The totalValue should get the correct value regardless of whether all pertinent OrderDetails were loaded. (This probably means running an UPDATE statement with SUM(value) in during flush/commit.)
    - Various permutation about which fields in Order were modified by the current and the other application, and doing the Right Thing in each case (too much detail for a single post so I'm leaving that out for now).
    BTW Hibernate doesn't do this, so supporting that use case would allow me to argue that we're not only getting rid of problems but actually getting something better than initially asked for :-)
    Not sure that I understood everything right; but you have transactions
    of course. And if two users deal with the same object, and user A does
    an update, the update gets reflected on the object of user B.

    Another thing which might be interesting for your case is that you can
    deal with multiple datacontext. In basics you can load an object into
    a datacontext X. You can load the same object into datacontext Y. Then
    you are able to modify it in context X and as long as you don't commit
    it, you can still work with the old values in datacontext Y. You can
    do some pretty cool stuff with that concept and even move objects
    between context.

    Grab a beer and have a look at this:
    http://cayenne.apache.org/doc/datacontext.html

    I guess you will like it very much.
    5. Those nested transactions (savepoints) are pretty cool and would be a major advantage. Sometimes we do have a series of steps and need to roll back some but not all of them (the "wizard situation").
    Are there caveats in that area, or can I go ahead and use that as a selling point without worrying about having to go back on that later?
    Sorry can't tell anything on that, did not use it myself
    6. How much manual work is involved in reverse engineering?
    For Hibernate, I found that the tool is only marginally better than simply specifying everything by hand. Maybe automatic reverse engineering generally isn't worth the hassle; after all, the tool only sees a VARCHAR(1) but cannot know whether it's just a boolean in disguise or a one-character status code, let alone guess the actual mapping between database strings and Java enum values. (We have lots of such things in our tables.)
    Honestly, you really should try it out. Download the package including
    the modeler, start it, define a database connection and of you go. Its
    pretty easy. I have tried it once and it worked like a charm for me. I
    needed it only once and could not find any problems. Hopefully it is
    fine for you too.

    One thing worth mentioning: Hibernate supports more Caching
    implementations like EHCache and others than Cayenne. Cayenne supports
    OpenSymphony Cache and recently an EHCache integration has been
    committed, but you have not the tons of caching systems supported by
    Hibernate. Anyway it is "pretty easy" to integrate one yourself.
    Anyway if you need that out of the box, better watch out

    Cheers!
    Christian
  • Michael Gentry at Aug 12, 2011 at 5:07 pm
    Hi Jo,

    Of course the answer is "yes" ... :-)

    More seriously, though, to maybe partially answer your questions:

    1) We do J2EE here, but pretty much in name only. We don't do EJBs or
    JMS, just web front-end and database back-end. That seems go cover an
    amazing amount of what we need to do. We are starting to use Cayenne
    more and more to talk to the database (Hibernate used to be the
    primary choice). One project is switching mainly due to Hibernate's
    LazyInitializationException and the number of man hours it takes to
    track those down in a complex web-based application. Cayenne doesn't
    have this exception, even in detached request/response oriented web
    applications.

    2) Do a few pet projects with Cayenne, especially if you don't come
    from an Enterprise Objects Framework/Web Objects background. You will
    really want to understand the Cayenne Data/Object Context. This is a
    concept missing in most other ORMs. Understanding how to use it can
    be a big hurdle for some.

    3) For me personally, I prefer the non-magic approach, especially when
    I need to step through the debugger to figure things out. Much easier
    when you don't go through proxies. Also, when going through a proxy,
    what you think is an instance of a User isn't really ...

    4) I didn't fully follow your #4. It sounds like you may want to
    allow concurrent updates, which is generally discouraged. As for
    updating the Order.totalValue, you could override the setter for
    OrderDetail.setValue() to re-calculate, but that would also require
    all the OrderDetails to be loaded.

    5) You may want nested DataContexts here.

    6) The amount of work involved depends a lot upon your schema.
    Cayenne will give you a good start, usually. You'll have to go clean
    some things up, like your VARCHAR(1) example. Since you mention
    enums, Cayenne does let you map Java enums to arbitrary int/varchar
    values (your Java name doesn't have to match the value stored in the
    DB). Say your Order table has a status column and one of the values
    is "P" for pending. You could say in your Java (where OrderStatusType
    is an enum): order.setStatus(OrderStatusType.PENDING). You don't have
    to use strings, plus the SQL logging is nicer (shows PENDING gets
    mapped to a "P").

    mrg


    On Fri, Aug 12, 2011 at 10:36 AM, Durchholz, Joachim
    wrote:
    Well of course your answer will be Yes :-)
    So, more specifically, I'm interested in hearing about the relative strengths and weaknesses of sessionless ORMs, e.g. Ebean.

    I'd like to hear opinion, trench stories, and such.

    Here's some things I that may or may not be relevant, any feedback welcome:

    1. I'm in a J2SE project. There are wishes to convert that into J2EE, or at least partition the J2SE app into a J2EE-compatible service layer and a GUI. (There is also a nightly batch app that I don't see ever arriving in J2EE land. No use case for that.)

    2. I can't take any risks. The project is in bad standing already because of all the time (more than a person-year) sunk into identifying and solving Hibernate hassles; another delay on that order of magnitude and I'm out of my current job. I can probably convince my higher-ups to sink another person-month into getting away from Hibernate, but I need to give solid guarantees.
    So: any feedback from people who have done that kind of transition would be very, very much appreciated, with a particular emphasis on traps to avoid.

    3. I have no LOBs, no wide tables, and all bulk data goes over gigabit ethernet so I don't need no fieldwise laziness.
    However, I have no experience with a framework that does not use bytecode generation, so I'm curious how the differences turn out in practice.
    So... what do people think about pros and cons of runtime bytecode generation?

    4. I'd like to ensure stuff like "Order.totalValue needs to be the sum of all associated OrderDetail.value fields".
    "Interesting" aspects here:
    - Other applications might have modified OrderDetail records during user think time. I'd prefer the ORM simply updating the totalValue to whatever is in the database over getting a concurrent modification complaint (unless the current app loaded the same OrderDetail and changed the value field to something different).
    - The totalValue should get the correct value regardless of whether all pertinent OrderDetails were loaded. (This probably means running an UPDATE statement with SUM(value) in during flush/commit.)
    - Various permutation about which fields in Order were modified by the current and the other application, and doing the Right Thing in each case (too much detail for a single post so I'm leaving that out for now).
    BTW Hibernate doesn't do this, so supporting that use case would allow me to argue that we're not only getting rid of problems but actually getting something better than initially asked for :-)

    5. Those nested transactions (savepoints) are pretty cool and would be a major advantage. Sometimes we do have a series of steps and need to roll back some but not all of them (the "wizard situation").
    Are there caveats in that area, or can I go ahead and use that as a selling point without worrying about having to go back on that later?

    6. How much manual work is involved in reverse engineering?
    For Hibernate, I found that the tool is only marginally better than simply specifying everything by hand. Maybe automatic reverse engineering generally isn't worth the hassle; after all, the tool only sees a VARCHAR(1) but cannot know whether it's just a boolean in disguise or a one-character status code, let alone guess the actual mapping between database strings and Java enum values. (We have lots of such things in our tables.)

    Regards,
    Jo

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
groupuser @
categoriescayenne
postedAug 12, '11 at 2:36p
activeAug 15, '11 at 9:18a
posts6
users5
websitecayenne.apache.org

People

Translate

site design / logo © 2022 Grokbase