Re: Conditional relationship mapping?

From: Aristedes Maniatis (ar..sh.com.au)
Date: Tue Mar 31 2009 - 10:51:18 EDT


On 31/03/2009, at 10:26 PM, Joseph Schmidt wrote:

> This would sound cool to me too, but from the Cayenne documentation
> example, this approach seems to have the problem that Java has
> single inheritance :(.
>
> If there's only one such table than it would work (single
> inheritance).
> E.g. In the above example, by doing a superclass to point to the
> "tag" table(Tag entity), called "Taggable". All entities that would
> like to have "tag"s would just need to extend the "Taggable" entity.
>
> The big problem is how to do it if there are more tables like that
> in the scheme :(.

Yes, you get to have exactly one Tag concept since you can have only
one superclass. Otherwise you have to model this as an interface, but
there is no support for that in Cayenne. You are on your own to
implement that, which brings you to choice 2.

You could lobby Sun for multiple inheritance, but you might be waiting
some time :-)

> This a very common scenario for Web2.0 apps (at least for the
> schemes I've seen so far) :(.
>
> Or has this something to do with "Horizontal Inheritance"?
> https://issues.apache.org/jira/browse/CAY-795

Horizontal, vertical, single-table. These ideas are only about the
database implementation and don't affect how the Java classes are
structured.

>> Choice 2:
>> Just do exactly what you are doing and fake the
>> relationships. Subclass CayenneContext so that you can
>> create the appropriate setters and getters to make this all
>> work. We do this ourselves and I might be able to dig up
>> some code if you get stuck.
> Are there any examples about this around?

You could download the onCourse server from our website (www.ish.com.au/oncourse)
  and open it up. Maybe download the Linux version since you can then
easily unzip the jar (the Windows one is bundled in exe wrappers).
Inside there you'll find our Cayenne model for the application (use
version 3 modeler to look at it). And in there, some tables called
Node and NodeRelation are of interest to you. In the application
itself, we use this to display 'Tags' attached to lots of different
entities: courses, students, etc.

Here's a snippet of code which then let's you find the related
records. In this Taggable is the interface, Node the "Tag" entity and
NodeRelation the join to other entities.

The main problem with it is that it doesn't scale well when you have
10,000 joins from one tag. The WHERE IN (...) sql clause doesn't scale
well with all databases. Inheritance can certainly be faster and
simpler.

        /**
         * Get a list of entity objects which are related to this node.
         *
         *..aram types restrict the entities which are to be returned to
these classes
         *..eturn list of related objects
         */
        public List<CayenneDataObject> getRelatedObjects(final Class<?
extends Taggable>[] types) {
                final List<NodeRelation> relations = getNodeRelations();
                final LinkedList<CayenneDataObject> result = new
LinkedList<CayenneDataObject>();

                // iterate through each of the types we are looking for
                for (final Class<? extends Taggable> classToFind : types) {

                        // now build a list of ids to find
                        String nodeIDs = null;
                        for (final NodeRelation relation : relations) {
                                if
(NodeRequirement
.getTaggableClasses
().get(classToFind).equals(relation.getEntityIdentifier())) {
                                        if (nodeIDs != null) {
                                                nodeIDs = nodeIDs + ",";
                                        }
                                        nodeIDs = nodeIDs + " " + relation.getEntityRecordId();
                                }
                        }

                        final HashMap<String, String> map = new HashMap<String, String>();
                        map.put("entityName",
NodeRequirement.getTaggableClasses().get(getClass()).toString());
                        final ObjEntity entity =
getObjectContext().getEntityResolver().lookupObjEntity(classToFind);
                        String whereString = "";
                        if (entity.getAttribute(_Course.IS_DELETED_PROPERTY) != null) {
                                whereString = "WHERE ((" + _Course.IS_DELETED_PROPERTY + " is NULL
OR " + _Course.IS_DELETED_PROPERTY + " = 0) AND id IN (" + nodeIDs +
"))";
                        } else {
                                whereString = "WHERE id IN (" + nodeIDs + ")";
                        }
                        map.put("whereClause", whereString);

                        final List<CayenneDataObject> list =
getObjectContext().performQuery(new NamedQuery("ObjectQuery", map));
                        if (list != null) {
                                result.addAll(list);
                        }
                }

                return result;
        }

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 : Tue Mar 31 2009 - 10:52:00 EDT