On 22/07/10 14:31, Samuel Gendler wrote:
> There's no one good answer to your question, although you've gone a
> long way to answering it with this: "while lazily fetching properties
> of entities to avoid downloading half the database whenever you query
> it for anything." Quite simply, you cannot allow the UI to access
> lazily fetched properties if you cannot tolerate the UI blocking while
> it loads.
Yeah, about what I feared.
It increasingly seems you can use JPA in desktop apps so long as you
don't want to provide a decent "experience" for the user, or don't mind
writing reams of boilerplate proxies that JPA is supposed to remove the
need for.
> I don't use JPA, but I do use hibernate, and removing the
> JPA layer gives me a much richer API for interacting with hibernate.
> I can write an HQL query which loads the properties that I know will
> be utilized in a particular context, avoiding lazy loading, even
> though my mappings support it (look for "join fetch" in the hibernate
> HQL docs).
The same is possible via JPA. The JPA query language is basically just HQL.
It still requires your app to know, in advance, what parts of what
objects will be required by what parts of the app. This becomes more of
a problem when you don't know what the user is going to do and how
they're going to interact with the objects, and you're using reusable
components that aren't aware of the nature of the objects they're
working with.
JPA (and ORM in general, including Hibernate etc) is "sold" on the
ability to use plain old java objects that map to database entities,
including using them as generic beans with any component or group of
components that works with beans. Yet, in reality, that just doesn't
work in any case where you need to pass in a large collection of
objects, only some of which will ever be examined in detail. You have to
load *all* the data for *all* the objects, just in case, or modify the
component to add JPA awareness that it's not supposed to need.
If you're going to do all that, and have to fight JPA's issues with
replacing whole object graphs in the process, using plain 'ol JDBC with
directly database-aware components starts to seem like a good idea. I
guess I'm just confused about why people seem to recommend using these
ORMs in Swing-based desktop apps, when they *REALLY* don't fit the Swing
event-driven non-blocking single-threaded programming model.
> I can disable lazy loading entirely in my mappings, or
> control it via my mappings and ensure that things are fetched in
> chunks larger than my UI displays them. When it comes to web services
> type apps, which often serialize objects out to a remote client, I use
> something like dozer to map my hibernate objects over to plain beans
> in my controller via a mapping that only copies the properties I care
> about, otherwise every request tends to get a copy of most of the db.
> Then the view deals only with the non-hibernate versions of your
> objects.
Ugh, so you work around the limitation with yet another layer of
abstraction / proxying?
I get the feeling I'd spend so long building layer after layer to work
around limitations that I might as well just write the code that does
just what I need in the first place. How do you find your approach as
compared to just using JDBC directly?
I'm particularly amazed that the NetBeans platform doesn't seem to cover
issues with UI blocking. There are tutorials on JPA use with NBP
everywhere, but they all just sweep the blocking/reliability issues
under the "it's just a tutorial" rug. This gives the poor reader the
idea that this might actually be a good idea, leading them straight into
a world of pain and suffering.
As it is, I'm considering tossing the whole swing/JPA app I have out the
window and prototyping something in grails that reuses my existing
mappings. It's that or build yet more infrastructure, possibly down to
cglib proxies, just to make JPA play well with Swing. Or build a
controller layer to proxy for my proxy entities. It's so Enterprise-y,
maybe I should do that!
*sigh*
Enterprise architecture: keeping programmers employed by doing as much
work as possible to achieve as little as possible by hiding everything
within ten or more pointless layers to work around the artificial
limitations of the previous layers.
( I actually have a working system in place for handling lazy loading,
dispatching reloads to the database while displaying a busy uI to the
user, etc. It's just ugly and very annoying. )
> I always wind up mapping to
> non-hibernate objects and then marshaling those, which adds latency
> and workload, though this is very unlikely to be noticeable on a
> single-user desktop app.
Ah, sorry, I may've been unclear. It's very definitely not single user,
it has many users interacting with a database over the network. Each
instance of the app is single-user, but they all share one database.
--
Craig Ringer