cayenne-user mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Michael Gentry" <blackn...@gmail.com>
Subject Re: Problem concerning Prefetching
Date Mon, 28 Jan 2008 16:02:49 GMT
Even with a one-to-many, Cayenne will still do the prefetches as
shown.  If you don't need everything at once, the batching idea
suggested by Ari will probably be your best bet.  Otherwise, you'll
need to figure out a non-typical way of fetching the data which works
right for your application.  This normally isn't too difficult to do.
Cayenne is great at the general case, but gives you the hooks to solve
custom, non-typical problems when needed.  Looking at your code, it
looks like you do indeed want to fetch it all in.

That being said, unless I'm missing something, you don't care too much
about having the Galaxy itself -- you are just using it to obtain the
properties, which is what you really want.  Why not invert your query?
 This is off the top of my head and is unlikely to compile, but
hopefully will make sense (note that you use the galaxy relationship
here):

public final List<GalaxyComponentProperties>
selectGalaxyComponentProperties(int timestep)
{
   StringBuffer buf = new StringBuffer("galaxy.halo.simulation.name = '");
   buf.append(getCurrentSimulationName());
   buf.append("' and galaxy.halo.properties.timestep = ");
   buf.append(timestep);

   Expression exp    = Expression.fromString(buf.toString());
   SelectQuery query = new SelectQuery(GalaxyComponentProperties.class, exp);
// fix this  query.addOrdering("number", true);

   //query.addPrefetch("componentProperties");

   return (List<GalaxyComponentProperties>) performQuery(query);
}

props = handler.selectGalaxyComponentProperties(ts);

for (GalaxyComponentProperties prop : props) {
//   GalaxyComponentProperties prop = g.getComponentProperties("disc");
   if (prop != null) {
       printer.println(g.getNumber() + ", " +
                       prop.getMassOfBaryons().toString());
   }
}


Also, since I tend to worry about security a bit, the following bit of
code could allow for SQL injection (which is bad) if you are getting
the data from an external source:

   StringBuffer buf = new StringBuffer("halo.simulation.name = '");
   buf.append(getCurrentSimulationName());
   buf.append("' and halo.properties.timestep = ");
   buf.append(timestep);

It is much better to use bindings, such as:

    map = new HashMap(2);
    expression = Expression.fromString("halo.simulation.name =
$simulationName and halo.properties.timestep = $timeStep");
    map.put("simulationName", getCurrentSimulationName());
    map.put("timeStep", new Integer(timestep));
    query  = new SelectQuery(Galaxy.class, expression.expWithParameters(map));

When using bindings, Cayenne (and the JDBC drivers) remove SQL
injection as a security issue.  When you construct the values
yourself, it is less secure.

Hope that helps,

/dev/mrg



On Jan 28, 2008 10:29 AM, Jean-Paul Le Fèvre <jean-paul.lefevre@cea.fr> wrote:
> On Monday 28 January 2008, Michael Gentry wrote:
> > Hi Jean-Paul,
>
> Hi Michael and Andrus,
>
> >
> > It looks like galaxy -> galaxy_component_properties is a to-one
> > relationship, which would cause Cayenne to issue multiple selects like
> > this since it tries to resolve each fault individually.
>
> It's a one to many : each galaxy has 3 different types of properties.
>
> Here is the code (simplified) implementing my method :
>
> public final List<Galaxy> selectGalaxies(int timestep)
> {
>     StringBuffer buf = new StringBuffer("halo.simulation.name = '");
>     buf.append(getCurrentSimulationName());
>     buf.append("' and halo.properties.timestep = ");
>     buf.append(timestep);
>
>     Expression exp    = Expression.fromString(buf.toString());
>     SelectQuery query = new SelectQuery(Galaxy.class, exp);
>     query.addOrdering("number", true);
>
>     //query.addPrefetch("componentProperties");
>
>     return (List<Galaxy>) performQuery(query);
> }
>
> And here is how I use it :
> galaxies = handler.selectGalaxies(ts);
>
> // Loop on galaxies, get the disc component and the mass of baryons.
> for (Galaxy g : galaxies) {
>
>     GalaxyComponentProperties prop = g.getComponentProperties("disc");
>     if (prop != null) {
>         printer.println(g.getNumber() + ", " +
>                         prop.getMassOfBaryons().toString());
>     }
> }
>
> >
> > Given your manual SQL statement:
> >
> > select galaxies.number, galaxy_component_properties.mass_of_baryons
> >       from galaxy_component_properties
> >       join galaxies on galaxy_component_properties.galaxy_id = galaxies.id
> >       where some_clause
> >       order by galaxies.number;
> >
> > It looks like you don't actually care about having actual Cayenne
> > objects (it looks like you only care about having two of the
> > attributes)?  If this is the case, you could use an SQLTemplate and
> > raw data rows to only fetch in those two properties.  If this isn't
> > the case, let us know and we'll give you other ideas.
>
> In fact you asked the good question. I'm just at the beginning of the
> development and I don't really know how the application will be used and as a
> consequence it is hard to figure out what it the best strategy to implement
> the functionalities : I guess that some users are only interested in
> computing mean values, sums, min, max  in big chunks of data but others want
> to retrieve all the attributes of a small amount of specific objects. The
> challenge is to make both types of users happy. I'm wondering whether it is
> possible or not.
> In my experience Cayenne has always been excellent at manipulating small
> numbers of complex objects but, on the other hand, difficult to use on huge
> dataset.
>
>
>
>
> --
> ___________________________________________________________________
>
> Jean-Paul Le Fèvre  * Mail : LeFevre@fonteny.org
>
>

Mime
View raw message