FAQ
Is it possible for Cayenne(and the Modeler) to map conditional relationships?

I have a table, e.g. "tag" that relates to too many other tables, but one row is always related only to one table. This is done by having
instead of many foreign keys columns, just with 2 in a generic way:
- 'related_table' contains the name of the target table, and
- 'related_row_id' is the 'id' of the row in the target table.

I see this scenario in many schemes lately, where at least 3 or 4
tables behave like the above "tag" table.

Is it possible to map efficiently such a scenario with Cayenne(and the modeler)? If it is, how?

thanks,
Joseph.

Search Discussions

  • Joseph Schmidt at Mar 31, 2009 at 10:36 am

    Is it possible for Cayenne(and the Modeler) to map
    conditional relationships?

    I have a table, e.g. "tag" that relates to too many other
    tables, but one row is always related only to one table.
    This is done by having
    instead of many foreign keys columns, just with 2 in a
    generic way:
    - 'related_table' contains the name of the target table,
    and
    - 'related_row_id' is the 'id' of the row in the target
    table.

    I see this scenario in many schemes lately, where at least
    3 or 4
    tables behave like the above "tag" table.

    Is it possible to map efficiently such a scenario with
    Cayenne(and the modeler)? If it is, how?
    Any idea how to do this?
    Or is it possible at all with Cayenne such scenarios?

    thanks,
    Joseph.
  • Aristedes Maniatis at Mar 31, 2009 at 10:58 am

    On 29/03/2009, at 4:28 AM, Joseph Schmidt wrote:
    Is it possible for Cayenne(and the Modeler) to map conditional
    relationships?

    I have a table, e.g. "tag" that relates to too many other tables,
    but one row is always related only to one table. This is done by
    having
    instead of many foreign keys columns, just with 2 in a generic way:
    - 'related_table' contains the name of the target table, and
    - 'related_row_id' is the 'id' of the row in the target table.

    I see this scenario in many schemes lately, where at least 3 or 4
    tables behave like the above "tag" table.

    Is it possible to map efficiently such a scenario with Cayenne(and
    the modeler)? If it is, how?

    Choice 1:
    This looks a lot like inheritance. Explore the various options
    available to you there, particularly in Cayenne 3. This is the
    'proper' way to do it. Most of the time.

    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.


    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
  • Joseph Schmidt at Mar 31, 2009 at 11:27 am
    Thank you very much for your reply.
    Is it possible for Cayenne(and the Modeler) to map
    conditional relationships?
    I have a table, e.g. "tag" that relates to too many
    other tables, but one row is always related only to one
    table. This is done by having
    instead of many foreign keys columns, just with 2 in a
    generic way:
    - 'related_table' contains the name of the target
    table, and
    - 'related_row_id' is the 'id' of the row in the
    target table.
    I see this scenario in many schemes lately, where at
    least 3 or 4
    tables behave like the above "tag" table.

    Is it possible to map efficiently such a scenario with
    Cayenne(and the modeler)? If it is, how?


    Choice 1:
    This looks a lot like inheritance. Explore the various
    options available to you there, particularly in Cayenne 3.
    This is the 'proper' way to do it. Most of the time.
    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 :(.

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

    thanks,
    Joseph.
  • Aristedes Maniatis at Mar 31, 2009 at 2:51 pm

    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.
    *
    * @param types restrict the entities which are to be returned to
    these classes
    * @return 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

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
groupuser @
categoriescayenne
postedMar 28, '09 at 5:28p
activeMar 31, '09 at 2:51p
posts5
users2
websitecayenne.apache.org

People

Translate

site design / logo © 2022 Grokbase