Sorry, the subject was wrong, as I started writing a message about
something entirely different initially :-)
On Dec 27, 2007, at 12:53 PM, Andrus Adamchik wrote:
BTW, here is another data point for this discussion. Here is a type-
safe bean framework written by one of the Cayenne users:
http://ujoframework.pponec.net/
The framework itself has no direct relation to Cayenne, but I wonder
if with proper code generation, we could use a similar approach of
type-safe property declaration to achieve type safety in the
ExpressionFactory methods. The fact that Cayenne doesn't tell you
that you can't match say a String against a BigDecimal in an
Expression has been causing some grief to our users already.
Andrus
On Dec 27, 2007, at 10:50 AM, Aristedes Maniatis wrote:
On 27/12/2007, at 1:29 AM, Mike Kienenberger wrote:
String pathSpec = Artist.ARTIST_NAME_PROPERTY;
or
String pathSpec = Painting.ARTIST_PROPERTY + "." +
Artist.ARTIST_NAME_PROPERTY;
Note also, that the pastSpec has the same suffix -- all you need
to do
is adjust the prefix to account for a different root:
But that is exactly my point: the Expression object is different
depending on where the root of the query starts. Sure the end part
of the expression is the same, but that doesn't help anyone reuse
an Expression object and so it is intrinsically tied to a root
entity.
Andrus's point is that they can be reused if you happen to name
your properties the same between multiple entities, but the thought
hadn't even occurred to me that this would be useful - I'd consider
it poor practice to make these sorts of assumptions about the
model. Someone could change the model and break a whole lot of code
without a single compile time exception.
Expression e = ExpressionFactory.matchExp(Painting.NAME_PROPERTY,
"bob");
Sure, the Painting.NAME_PROPERTY and Artist.NAME_PROPERTY might
both be equal("name") and the above expression will work for both
artists called bob and paintings called bob. But does anyone
actually use Cayenne like this? What happens when someone changes
Artist.NAME_PROPERTY to Artist.LASTNAME_PROPERTY?
Could it then make sense to do this:
1. Expression<Artist> e =
ExpressionFactory.matchExp(Artist.NAME_PROPERTY, "bob",
Artist.class);
2. e = e.andExpr(ExpressionFactory.matchExp(Artist.SUBURB_PROPERTY,
"Newtown", Artist.class));
3. e = e.andExpr(ExpressionFactory.matchExp(Artist.STATE_PROPERTY,
"NSW")); <--- no compile time checking here
4. e = e.andExpr(ExpressionFactory.matchExp(Artist.NAME_PROPERTY,
"bob", Painting.class)); <--- oops, error here
The benefits:
* when combining expressions (eg. andExp) type safety can be
enforced at compile time (if the root class is passed for each
expression which makes up the whole)
* the root entity class can flow through to query without needing
to be passed again: simpler, cleaner API. Expression and Query get
generified together.
* works like EJBQL which people will probably get to know over time
The cons:
* can't use the trick of sharing expressions across properties with
identical names from several entities
* something makes me think that line 3 may run into problems with
generics internal to Cayenne code and we will not be able to force
the cast of <?> into <Artist>. But I remain hopeful that there is a
way, and even if not it doesn't kill the idea, just make it more
awkward to use when building long compound expressions.
* significant change to the previous API (but if we are going to
force people to make a change, better that it be done as best we
can right now)
I know this is just half the problem (the other half is how to
decide whether you are getting datarows or some other type back
from a query), so I just throw this up as an idea. To my mind it is
the philosophically appropriate place to inject the root entity.
Ari Maniatis
-------------------------->
ish
http://www.ish.com.au
Level 1, 30 Wilson Street Newtown 2042 Australia
phone +61 2 9550 5001 fax +61 2 9550 4001
GPG fingerprint CBFB 84B4 738D 4E87 5E5C 5EFA EF6A 7D2E 3E49 102A