Typesafe property declarations [Was: ExpressionFactory -> ExpressionBuilder [Was: performQuery generics]]

From: Andrus Adamchik (andru..bjectstyle.org)
Date: Thu Dec 27 2007 - 05:54:59 EST

  • Next message: Aristedes Maniatis: "Re: performQuery generics"

    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
    >>
    >>
    >>
    >
    >



    This archive was generated by hypermail 2.0.0 : Thu Dec 27 2007 - 05:55:35 EST