FAQ
Hi,

Cayenne is now getting nearer to "we may actually try this" status here, mostly because Hibernate keeps making things complicated.
Which means I'm going to ask some rather specific and convoluted questions; please feel free to answer just some of them.


1) Does anybody have concrete advice about using Cayenne without Modeler?

Background:
I see Modeler is one of the major sources of "huh?" moments on the list. It's an additional layer of abstraction between what Cayenne does and what the developer sees, meaning it can introduce problems (and occasionally does); I'd want to get my feet wet with Cayenne without that complication.
I also see it's the one part that you actually can avoid using - the XML can be edited by hand.

Now the potential problems I see with hand-editing the XML:

1a) Is there a DTD? Without a DTD, hand editing becomes too cumbersome and error-prone.

1b) Does Cayenne offer a way to check consistency between XML and a database? (I wouldn't object to using Modeler for that limited purpose. That might even be a good way to getting used to Modeler's view of the data model. I guess the answer is "yes", the modeler docs talk about "Validation of created mappings", but it would be nice to confirm I'm not misunderstanding something here.)

1c) If there's a way to check consistency, are inconsistencies reported in a way that a Cayenne newbie would understand? Such error messages can be difficult to generate, they'd need to detail both the involved RDBMS concepts (tables, fields, lengths, precisions, FKs etc.) and the involved Cayenne concepts (class definitions, associations). And since an error means these are out of sync, the error message would need to be as precise as possible about the nature of the inconsistency, which is no mean feat.


2) How would one assign a "field type" with a field in a Cayenne Pojo?

With "field type", I mean things like
123456789012345678901234567890123456789012345678901234567890123456789012
- Associating textual representation with field contents, such as
-- shorthands in the database table, Java enums internally,
longer texts on display
-- or maybe shorthands in the database table, Java Strings internally,
longer texts on display
- What Swing controls to use for displaying this data
("Renderer" in Swing terminology)
- What Swing controls to use for editing this data
("Editor" in Swing terminology)
- Validation info: valid ranges; probably a Java interface with
implementations that may or may not use RDBMS length/precision info
- Possibly association with more than one field
(date/time in two fields but merged into one Java property)
(or still two Java properties, but validation etc. spans all of them)

I see various possible approaches:

2a) The traditional Cayenne approach. Make the entity class a superclass, the business class a subclass. Entity class properties would have private members and protected getters/setters, the business class would then use a FieldType object to delegate public getters/setters to the protected getters/setters. (FieldType objects would be static and accept entity objects as parameters, so memory bloat isn't an issue. I'm using a similar construction in my current Hibernate infrastructure.)
I'm a bit worried about the amount of boilerplate needed in the business class. In particular for the trivial cases where the DB field is simply handed through to the business logic (e.g. address fields where the end user should be able to put in pretty anything they choose as long as it fits the database field).

2b) Use delegation instead of subclassing. The issues are essentially the same, except the getters/setters of the entity class wouldn't have to be package-private or public instead of protected.
Are there other issues that I should be aware of?

2c) Since I'm not too dependent on Modeler, I might merge entity and business class.
I'm not sure that such a merge has any advantages; does anybody have seen this tried? Stories of failure and success equally interesting here.
I have to admit I don't expect success, merging abstractions usually doesn't work well in the long term; losing the option to use Modeler's code generation later when we're more confident in it is a strong point agains that route, too. Still, I'd like to know how much water this assessment holds.

2d) Anything I haven't thought of. Different ways to use Java reflection, a Modeler option I'm not aware of that does all these things out of the box, whatever.


3) How do I do cascading?

I have seen some mention of this in the docs but haven't found a comprehensive description.

3a) Less is more. Abstract is better than concrete.
Hibernate shows how not do do this: theres roughly half a dozen cascale options for each association, each labelled with the name of one database-level operation, but little or no documentation on what high-level operation invokes which database-level cascade.
How's this done in Cayenne?

3b) Is there a way to do a cascading "check for inconsistencies between entity objects in the persistence context and database rows"?
One approach to that might be a full reload of all objects and reporting back if there are inconsistent updates.
Another might be some forced update on the dependent object, so only the master objects "above" a changed object need to be checked, then updated.

The background is that we want to allow the occasional inconsistency introduced via manual updates, but not via the application.
We do have consistency conditions that aren't easily enforced using database constraints or update triggers (besides, an update trigger would require a reload from the application, so now I have to do the are-we-still-in-sync check anyway).


4) Can I do mixed scalar/object queries?

I need to retrieve a list of entities, plus some statistical data.
In SQL terms, this might look like
SELECT orders.*, SUM(detail.itemprice * detail.quantity), COUNT(detail.id)
GROUP BY <all fields of table "orders" here>
Yes, I want to keep the detail counting, multiplying and sorting on the database server, to keep network traffic down.
I'd also want to get all fields of the "orders" table in an Orders Pojo.
The result of the query would either be an Object[], or a Javabean with fields for the Orders object, a BigDecimal for the total price and a BigInteger for the detail count.
(I haven't found a way to do this efficiently in Hibernate. I have spent more than a week on this and am approaching the point where switching to Cayenne would have been less work. Presumably ;-/ )
http://cayenne.apache.org/doc30/sqltemplate-result-mapping.html indicates that this is indeed possible - is that correct? Did somebody use it in anger already?


Any feedback welcome :-)

Regards,
Jo

Search Discussions

  • John Huss at Jan 18, 2012 at 4:55 pm
    Here are a few answers.
    On Wed, Jan 18, 2012 at 9:33 AM, Durchholz, Joachim wrote:

    Hi,

    Cayenne is now getting nearer to "we may actually try this" status here,
    mostly because Hibernate keeps making things complicated.
    Which means I'm going to ask some rather specific and convoluted
    questions; please feel free to answer just some of them.


    1) Does anybody have concrete advice about using Cayenne without Modeler?

    Background:
    I see Modeler is one of the major sources of "huh?" moments on the list.
    It's an additional layer of abstraction between what Cayenne does and what
    the developer sees, meaning it can introduce problems (and occasionally
    does); I'd want to get my feet wet with Cayenne without that complication.
    I also see it's the one part that you actually can avoid using - the XML
    can be edited by hand.
    I don't see this as reducing complexity, rather it increases it since the
    tool is much easier to use and understand than an XML file. Having a model
    representation that is separate from the java files (i.e. not using
    embedded java annotations) is a big strength for Cayenne compared to
    Hibernate/JPA. The tool makes it both easier and better.

    Now the potential problems I see with hand-editing the XML:

    1a) Is there a DTD? Without a DTD, hand editing becomes too cumbersome and
    error-prone.
    There is a schema:

    <?xml version="1.0" encoding="utf-8"?>

    <data-map xmlns="http://cayenne.apache.org/schema/3.0/modelMap" xmlns:xsi="
    http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="
    http://cayenne.apache.org/schema/3.0/modelMap
    http://cayenne.apache.org/schema/3.0/modelMap.xsd" project-version="6">
    1b) Does Cayenne offer a way to check consistency between XML and a
    database?

    Yes

    (I wouldn't object to using Modeler for that limited purpose. That might
    even be a good way to getting used to Modeler's view of the data model. I
    guess the answer is "yes", the modeler docs talk about "Validation of
    created mappings", but it would be nice to confirm I'm not misunderstanding
    something here.)

    1c) If there's a way to check consistency, are inconsistencies reported in
    a way that a Cayenne newbie would understand? Such error messages can be
    difficult to generate, they'd need to detail both the involved RDBMS
    concepts (tables, fields, lengths, precisions, FKs etc.) and the involved
    Cayenne concepts (class definitions, associations). And since an error
    means these are out of sync, the error message would need to be as precise
    as possible about the nature of the inconsistency, which is no mean feat.


    2) How would one assign a "field type" with a field in a Cayenne Pojo?

    With "field type", I mean things like
    123456789012345678901234567890123456789012345678901234567890123456789012
    - Associating textual representation with field contents, such as
    -- shorthands in the database table, Java enums internally,
    longer texts on display
    -- or maybe shorthands in the database table, Java Strings internally,
    longer texts on display
    - What Swing controls to use for displaying this data
    ("Renderer" in Swing terminology)
    - What Swing controls to use for editing this data
    ("Editor" in Swing terminology)
    - Validation info: valid ranges; probably a Java interface with
    implementations that may or may not use RDBMS length/precision info
    - Possibly association with more than one field
    (date/time in two fields but merged into one Java property)
    (or still two Java properties, but validation etc. spans all of them)
    The objects in the data map (entites, attributes, etc) aren't extensible
    with arbitrary data currently (webobjects has this with the userInfo
    dictionary / hashmap). But you could create separate file in your own
    format that contains additional model information.

    I see various possible approaches:

    2a) The traditional Cayenne approach. Make the entity class a superclass,
    the business class a subclass. Entity class properties would have private
    members and protected getters/setters, the business class would then use a
    FieldType object to delegate public getters/setters to the protected
    getters/setters. (FieldType objects would be static and accept entity
    objects as parameters, so memory bloat isn't an issue. I'm using a similar
    construction in my current Hibernate infrastructure.)
    I'm a bit worried about the amount of boilerplate needed in the business
    class. In particular for the trivial cases where the DB field is simply
    handed through to the business logic (e.g. address fields where the end
    user should be able to put in pretty anything they choose as long as it
    fits the database field).

    2b) Use delegation instead of subclassing. The issues are essentially the
    same, except the getters/setters of the entity class wouldn't have to be
    package-private or public instead of protected.
    Are there other issues that I should be aware of?

    2c) Since I'm not too dependent on Modeler, I might merge entity and
    business class.
    I'm not sure that such a merge has any advantages; does anybody have seen
    this tried? Stories of failure and success equally interesting here.
    I have to admit I don't expect success, merging abstractions usually
    doesn't work well in the long term; losing the option to use Modeler's code
    generation later when we're more confident in it is a strong point agains
    that route, too. Still, I'd like to know how much water this assessment
    holds.
    You can combine the _Entity and Entity classes. These are separated merely
    for convenience (this is the Generation Gap pattern) so you can utilize the
    code generation without overwriting your custom logic.

    2d) Anything I haven't thought of. Different ways to use Java reflection,
    a Modeler option I'm not aware of that does all these things out of the
    box, whatever.
    I'm not sure what you're trying to achieve here. Do you want to isolate
    Cayenne so that it is not "polluting" your business objects?

    Regardless, you will want to use Cayenne's code generation. The templates
    are totally configurable so you can make it do whatever you like. The code
    generation is available via Modeler, ant, or the eclipse plugin.


    3) How do I do cascading?

    I have seen some mention of this in the docs but haven't found a
    comprehensive description.

    3a) Less is more. Abstract is better than concrete.
    Hibernate shows how not do do this: theres roughly half a dozen cascale
    options for each association, each labelled with the name of one
    database-level operation, but little or no documentation on what high-level
    operation invokes which database-level cascade.
    How's this done in Cayenne?

    3b) Is there a way to do a cascading "check for inconsistencies between
    entity objects in the persistence context and database rows"?
    One approach to that might be a full reload of all objects and reporting
    back if there are inconsistent updates.
    Another might be some forced update on the dependent object, so only the
    master objects "above" a changed object need to be checked, then updated.

    The background is that we want to allow the occasional inconsistency
    introduced via manual updates, but not via the application.
    We do have consistency conditions that aren't easily enforced using
    database constraints or update triggers (besides, an update trigger would
    require a reload from the application, so now I have to do the
    are-we-still-in-sync check anyway).


    4) Can I do mixed scalar/object queries?

    I need to retrieve a list of entities, plus some statistical data.
    In SQL terms, this might look like
    SELECT orders.*, SUM(detail.itemprice * detail.quantity), COUNT(detail.id
    )
    GROUP BY <all fields of table "orders" here>
    Yes, I want to keep the detail counting, multiplying and sorting on the
    database server, to keep network traffic down.
    I'd also want to get all fields of the "orders" table in an Orders Pojo.
    The result of the query would either be an Object[], or a Javabean with
    fields for the Orders object, a BigDecimal for the total price and a
    BigInteger for the detail count.
    (I haven't found a way to do this efficiently in Hibernate. I have spent
    more than a week on this and am approaching the point where switching to
    Cayenne would have been less work. Presumably ;-/ )
    http://cayenne.apache.org/doc30/sqltemplate-result-mapping.html indicates
    that this is indeed possible - is that correct? Did somebody use it in
    anger already?
    I haven't done this. QueryChain (I think that's what it's called) will let
    you send multiple queries in one trip to the DB. But if you want a single
    query with diverse results then your suggestion will probably work better.

    John
  • Durchholz, Joachim at Jan 19, 2012 at 1:56 pm
    Here are a few answers.
    Thanks!
    Very much appreciated.
    1) Does anybody have concrete advice about using Cayenne without Modeler?

    Background:
    I see Modeler is one of the major sources of "huh?" moments on the list.
    It's an additional layer of abstraction between what Cayenne does and
    what the developer sees, meaning it can introduce problems (and
    occasionally does); I'd want to get my feet wet with Cayenne without that complication.
    I also see it's the one part that you actually can avoid using - the
    XML can be edited by hand.
    I don't see this as reducing complexity, rather it increases it since the
    tool is much easier to use and understand than an XML file.
    Hm... well, Modeler adds a level of interpretation (if only implicitly) between user and XML.
    For example, that "To Dep PK" checkbox doesn't sound quite self-explanatory.

    Of course, it essentially depends on what's better documented: the XML or Modeler :-)
    Having a model representation that is separate from the java files
    (i.e. not using embedded java annotations) is a big strength for Cayenne
    compared to Hibernate/JPA.
    I see it the other way round: if the Java code and the specifications that it depends on are in the same file, it's easier to spot problems.
    Of course, if the Java code in question is generated anyway, the question is moot.
    The tool makes it both easier and better.
    Noted. Thanks.

    Now the potential problems I see with hand-editing the XML:

    1a) Is there a DTD? Without a DTD, hand editing becomes too cumbersome
    and error-prone.
    There is a schema:

    <?xml version="1.0" encoding="utf-8"?>

    <data-map xmlns="http://cayenne.apache.org/schema/3.0/modelMap" xmlns:xsi="
    http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="
    http://cayenne.apache.org/schema/3.0/modelMap
    http://cayenne.apache.org/schema/3.0/modelMap.xsd" project-version="6">

    Sweet :-)
    1b) Does Cayenne offer a way to check consistency between XML and a
    database?
    Yes
    Just through modeler, or is it available through an Ant task or its Maven equivalent?
    Half a bonus point if it's in the Cayenne runtime jars since it would save me a configuration step :-)
    2) How would one assign a "field type" with a field in a Cayenne Pojo?
    The objects in the data map (entites, attributes, etc) aren't extensible
    with arbitrary data currently (webobjects has this with the userInfo
    dictionary / hashmap).
    I guess I'll go with the _Entity/Entity split then.
    It's not a very big deal anyway.
    2d) Anything I haven't thought of. Different ways to use Java
    reflection, a Modeler option I'm not aware of that does all these
    things out of the box, whatever.
    I'm not sure what you're trying to achieve here.
    Just exploring possibilities.
    Delegation would give me more independence from the generated code, at the expense of some memory usage (which could become relevant since some of the things we do are bulk operations on hundreds of thousands of objects; some of the operations haven't been split into reasonably-sized auto-continuing transactions yet).
    Do you want to isolate Cayenne so that it is not "polluting" your business objects?
    That is a factor in the back of my mind, but I think that can be handled using private fields and protected getters/setters and should not become a problem.
    Regardless, you will want to use Cayenne's code generation. The
    templates are totally configurable so you can make it do whatever
    you like.
    I'm extremely wary of modifying templates. It means I have to revisit them on each and every Cayenne update to see whether the basic machinery has changed and I need to redo my modifications.

    Also, for some reason, templates tend to be hard to modify.
    I tend to whince whenever I hear the word :-)
    I don't know how it is for Cayenne though; among the problems I have seen elsewhere are:
    -
    The code generation is available via Modeler, ant, or the eclipse plugin.
    That's very good.

    Regards & thanks,
    Jo
  • Mike Kienenberger at Jan 19, 2012 at 2:18 pm

    On Thu, Jan 19, 2012 at 8:55 AM, Durchholz, Joachim wrote:
    Delegation would give me more independence from the generated code, at the expense of some memory usage (which could become relevant since some of the things we do are bulk operations on hundreds of thousands of objects; some of the operations haven't been split into reasonably-sized auto-continuing transactions yet).
    It's trivial to change the template to generate delegation patterns
    instead. I've done that in a project where either Cayenne or JPA
    could be used as the backend. In fact, I used Cayenne templates to
    generate both backends.


    The same project also worked with an in-house system where all of the
    "authoritative" metadata was stored in a database. I wrote a simple
    extension to the modeler to automatically "import" from the metadata
    rather than the xml file, and then resave it to a standard cayenne
    format.

    I'm extremely wary of modifying templates. It means I have to revisit them on each and every Cayenne update to see whether the basic machinery has changed and I need to redo my modifications.
    The templates are standard velocity templates with a very few number
    of cayenne-specific attributes predefined.

    I am fairly certain that the templating tasks have only changed once
    in the last 8 years -- I did the upgrade -- and when they did change,
    full backward compatibility was left in as an option. I am not
    using the 3.x branch yet, but I would expect that Cayenne 1.1
    templates created back in 2004 would work just as well today.

    Yes, it's always possible that the basic data structure behind the
    Cayenne mapping could change, but I don't think that's happened yet,
    other than perhaps new additions, which shouldn't affect older models.
  • Durchholz, Joachim at Jan 19, 2012 at 4:45 pm

    The same project also worked with an in-house system where all of the
    "authoritative" metadata was stored in a database. I wrote a simple
    extension to the modeler to automatically "import" from the metadata
    rather than the xml file, and then resave it to a standard cayenne format.
    Oh... you can write extensions to Modeler?
    Is there an official interface for that?

    Thanks for the other infos.

    Regards,
    Jo
  • Mike Kienenberger at Jan 19, 2012 at 5:12 pm

    On Thu, Jan 19, 2012 at 11:44 AM, Durchholz, Joachim wrote:
    Oh... you can write extensions to Modeler?
    Is there an official interface for that?
    I don't think this made it into the official code. It was part of
    the tail-end of the last active Cayenne project I worked on before
    politics changed that project from Cayenne to JPA.

    I think I decided not to pursue it because (1) I wouldn't be around to
    maintain it, and (2) there was already ongoing discussion about the
    best way to allow modeler extensions.

    The actual changes to allow extensions is pretty simple and small,
    although "detecting" extensions in this version involves specifying an
    "org.apache.cayenne.modeler.cayenneActionPluginFactory" System
    property and including your extensions in the classpath.

    But at the time, it worked well enough for my purposes.

    I haven't followed the modeler development closely since then (2007?)
    so I am not sure what, if any, extensions points currently exist. My
    guess is that it would be easy for you integrate this into the current
    code base -- really, it's a quick easy hack to add menu items to
    various modeler menus.


    Index: E:/workspace311/cayenne-java/src/modeler/java/org/objectstyle/cayenne/modeler/CayenneModelerFrame.java
    ===================================================================
    --- E:/workspace311/cayenne-java/src/modeler/java/org/objectstyle/cayenne/modeler/CayenneModelerFrame.java (revision
    432015)
    +++ E:/workspace311/cayenne-java/src/modeler/java/org/objectstyle/cayenne/modeler/CayenneModelerFrame.java (working
    copy)
    @@ -60,6 +60,8 @@
    import java.awt.FlowLayout;
    import java.awt.Font;
    import java.awt.event.KeyEvent;
    +import java.util.Iterator;
    +import java.util.List;

    import javax.swing.Box;
    import javax.swing.JFrame;
    @@ -111,6 +113,8 @@
    import org.objectstyle.cayenne.modeler.event.ProcedureDisplayListener;
    import org.objectstyle.cayenne.modeler.event.QueryDisplayEvent;
    import org.objectstyle.cayenne.modeler.event.QueryDisplayListener;
    +import org.objectstyle.cayenne.modeler.plugin.CayenneActionPlugin;
    +import org.objectstyle.cayenne.modeler.plugin.CayenneActionPluginManager;
    import org.objectstyle.cayenne.modeler.util.CayenneAction;
    import org.objectstyle.cayenne.modeler.util.RecentFileMenu;

    @@ -209,6 +213,24 @@
    menuBar.add(fileMenu);
    menuBar.add(projectMenu);
    menuBar.add(toolMenu);
    +
    + List cayennePluginActionList =
    CayenneActionPluginManager.getInstance().getCayenneActionPluginList();
    + if (null != cayennePluginActionList)
    + {
    + JMenu pluginsMenu = new JMenu("Extensions");
    + if (!SystemUtils.IS_OS_MAC_OSX) {
    + pluginsMenu.setMnemonic(KeyEvent.VK_X);
    + }
    +
    + Iterator cayennePluginActionIterator =
    cayennePluginActionList.iterator();
    + while (cayennePluginActionIterator.hasNext()) {
    + CayenneActionPlugin cayennePluginAction =
    (CayenneActionPlugin) cayennePluginActionIterator.next();
    +
    pluginsMenu.add(getAction(cayennePluginAction.getActionName()).buildMenu());
    + }
    +
    + menuBar.add(pluginsMenu);
    + }
    +
    menuBar.add(helpMenu);

    setJMenuBar(menuBar);
    Index: E:/workspace311/cayenne-java/src/modeler/java/org/objectstyle/cayenne/modeler/ActionManager.java
    ===================================================================
    --- E:/workspace311/cayenne-java/src/modeler/java/org/objectstyle/cayenne/modeler/ActionManager.java (revision
    432015)
    +++ E:/workspace311/cayenne-java/src/modeler/java/org/objectstyle/cayenne/modeler/ActionManager.java (working
    copy)
    @@ -61,6 +61,7 @@
    import java.util.HashMap;
    import java.util.HashSet;
    import java.util.Iterator;
    +import java.util.List;
    import java.util.Map;

    import javax.swing.Action;
    @@ -100,6 +101,8 @@
    import org.objectstyle.cayenne.modeler.action.SaveAction;
    import org.objectstyle.cayenne.modeler.action.SaveAsAction;
    import org.objectstyle.cayenne.modeler.action.ValidateAction;
    +import org.objectstyle.cayenne.modeler.plugin.CayenneActionPlugin;
    +import org.objectstyle.cayenne.modeler.plugin.CayenneActionPluginManager;
    import org.objectstyle.cayenne.modeler.util.CayenneAction;

    /**
    @@ -167,6 +170,44 @@
    protected Map actionMap;

    public ActionManager(Application application) {
    +
    + List cayennePluginActionList =
    CayenneActionPluginManager.getInstance().getCayenneActionPluginList();
    + if (null != cayennePluginActionList)
    + {
    + Iterator cayennePluginActionIterator =
    cayennePluginActionList.iterator();
    + while (cayennePluginActionIterator.hasNext()) {
    + CayenneActionPlugin cayennePluginAction =
    (CayenneActionPlugin) cayennePluginActionIterator.next();
    + if (cayennePluginAction.isSpecialAction())
    + {
    + SPECIAL_ACTIONS.add(cayennePluginAction.getActionName());
    + }
    + if (cayennePluginAction.isProjectAction())
    + {
    + PROJECT_ACTIONS.add(cayennePluginAction.getActionName());
    + }
    + if (cayennePluginAction.isDomainAction())
    + {
    + DOMAIN_ACTIONS.add(cayennePluginAction.getActionName());
    + }
    + if (cayennePluginAction.isDataMapAction())
    + {
    + DATA_MAP_ACTIONS.add(cayennePluginAction.getActionName());
    + }
    + if (cayennePluginAction.isObjEntityAction())
    + {
    +
    OBJ_ENTITY_ACTIONS.add(cayennePluginAction.getActionName());
    + }
    + if (cayennePluginAction.isDbEntityAction())
    + {
    + DB_ENTITY_ACTIONS.add(cayennePluginAction.getActionName());
    + }
    + if (cayennePluginAction.isProcedureAction())
    + {
    + PROCEDURE_ACTIONS.add(cayennePluginAction.getActionName());
    + }
    + }
    + }
    +
    this.actionMap = new HashMap();

    registerAction(new ProjectAction(application));
    @@ -204,6 +245,16 @@
    registerAction(new ExitAction(application)).setAlwaysOn(true);
    registerAction(new
    NavigateBackwardAction(application)).setAlwaysOn(true);
    registerAction(new
    NavigateForwardAction(application)).setAlwaysOn(true);
    +
    + if (null != cayennePluginActionList)
    + {
    + Iterator cayennePluginActionIterator =
    cayennePluginActionList.iterator();
    + while (cayennePluginActionIterator.hasNext()) {
    + CayenneActionPlugin cayennePluginAction =
    (CayenneActionPlugin) cayennePluginActionIterator.next();
    +
    registerAction(cayennePluginAction.createCayenneAction(application));
    + }
    + }
    +
    }

    private CayenneAction registerAction(CayenneAction action) {
    Index: E:/workspace311/cayenne-java/src/modeler/java/org/objectstyle/cayenne/modeler/plugin/CayenneActionPlugin.java
    ===================================================================
    --- E:/workspace311/cayenne-java/src/modeler/java/org/objectstyle/cayenne/modeler/plugin/CayenneActionPlugin.java (revision
    0)
    +++ E:/workspace311/cayenne-java/src/modeler/java/org/objectstyle/cayenne/modeler/plugin/CayenneActionPlugin.java (revision
    0)
    @@ -0,0 +1,72 @@
    +/* ====================================================================
    + *
    + * The ObjectStyle Group Software License, version 1.1
    + * ObjectStyle Group - http://objectstyle.org/
    + *
    + * Copyright (c) 2002-2005, Andrei (Andrus) Adamchik and individual authors
    + * of the software. All rights reserved.
    + *
    + * Redistribution and use in source and binary forms, with or without
    + * modification, are permitted provided that the following conditions
    + * are met:
    + *
    + * 1. Redistributions of source code must retain the above copyright
    + * notice, this list of conditions and the following disclaimer.
    + *
    + * 2. Redistributions in binary form must reproduce the above copyright
    + * notice, this list of conditions and the following disclaimer in
    + * the documentation and/or other materials provided with the
    + * distribution.
    + *
    + * 3. The end-user documentation included with the redistribution, if any,
    + * must include the following acknowlegement:
    + * "This product includes software developed by independent contributors
    + * and hosted on ObjectStyle Group web site (http://objectstyle.org/)."
    + * Alternately, this acknowlegement may appear in the software itself,
    + * if and wherever such third-party acknowlegements normally appear.
    + *
    + * 4. The names "ObjectStyle Group" and "Cayenne" must not be used to endorse
    + * or promote products derived from this software without prior written
    + * permission. For written permission, email
    + * "andrus at objectstyle dot org".
    + *
    + * 5. Products derived from this software may not be called "ObjectStyle"
    + * or "Cayenne", nor may "ObjectStyle" or "Cayenne" appear in their
    + * names without prior written permission.
    + *
    + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
    + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
    + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    + * DISCLAIMED. IN NO EVENT SHALL THE OBJECTSTYLE GROUP OR
    + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
    + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
    + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
    + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
    + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    + * SUCH DAMAGE.
    + * ====================================================================
    + *
    + * This software consists of voluntary contributions made by many
    + * individuals and hosted on ObjectStyle Group web site. For more
    + * information on the ObjectStyle Group, please see
    + * <http://objectstyle.org/>.
    + */
    +package org.objectstyle.cayenne.modeler.plugin;
    +
    +import org.objectstyle.cayenne.modeler.Application;
    +import org.objectstyle.cayenne.modeler.util.CayenneAction;
    +
    +
    +public interface CayenneActionPlugin {
    + public String getActionName();
    + public CayenneAction createCayenneAction(Application application);
    + public boolean isSpecialAction();
    + public boolean isProjectAction();
    + public boolean isDomainAction();
    + public boolean isDataMapAction();
    + public boolean isObjEntityAction();
    + public boolean isDbEntityAction();
    + public boolean isProcedureAction();
    +}

    Index: E:/workspace311/cayenne-java/src/modeler/java/org/objectstyle/cayenne/modeler/plugin/CayenneActionPluginFactory.java
    ===================================================================
    --- E:/workspace311/cayenne-java/src/modeler/java/org/objectstyle/cayenne/modeler/plugin/CayenneActionPluginFactory.java (revision
    0)
    +++ E:/workspace311/cayenne-java/src/modeler/java/org/objectstyle/cayenne/modeler/plugin/CayenneActionPluginFactory.java (revision
    0)
    @@ -0,0 +1,63 @@
    +/* ====================================================================
    + *
    + * The ObjectStyle Group Software License, version 1.1
    + * ObjectStyle Group - http://objectstyle.org/
    + *
    + * Copyright (c) 2002-2005, Andrei (Andrus) Adamchik and individual authors
    + * of the software. All rights reserved.
    + *
    + * Redistribution and use in source and binary forms, with or without
    + * modification, are permitted provided that the following conditions
    + * are met:
    + *
    + * 1. Redistributions of source code must retain the above copyright
    + * notice, this list of conditions and the following disclaimer.
    + *
    + * 2. Redistributions in binary form must reproduce the above copyright
    + * notice, this list of conditions and the following disclaimer in
    + * the documentation and/or other materials provided with the
    + * distribution.
    + *
    + * 3. The end-user documentation included with the redistribution, if any,
    + * must include the following acknowlegement:
    + * "This product includes software developed by independent contributors
    + * and hosted on ObjectStyle Group web site (http://objectstyle.org/)."
    + * Alternately, this acknowlegement may appear in the software itself,
    + * if and wherever such third-party acknowlegements normally appear.
    + *
    + * 4. The names "ObjectStyle Group" and "Cayenne" must not be used to endorse
    + * or promote products derived from this software without prior written
    + * permission. For written permission, email
    + * "andrus at objectstyle dot org".
    + *
    + * 5. Products derived from this software may not be called "ObjectStyle"
    + * or "Cayenne", nor may "ObjectStyle" or "Cayenne" appear in their
    + * names without prior written permission.
    + *
    + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
    + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
    + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    + * DISCLAIMED. IN NO EVENT SHALL THE OBJECTSTYLE GROUP OR
    + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
    + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
    + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
    + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
    + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    + * SUCH DAMAGE.
    + * ====================================================================
    + *
    + * This software consists of voluntary contributions made by many
    + * individuals and hosted on ObjectStyle Group web site. For more
    + * information on the ObjectStyle Group, please see
    + * <http://objectstyle.org/>.
    + */
    +package org.objectstyle.cayenne.modeler.plugin;
    +
    +import java.util.List;
    +
    +
    +public interface CayenneActionPluginFactory {
    + public List getCayenneActionPluginList();
    +}

    Index: E:/workspace311/cayenne-java/src/modeler/java/org/objectstyle/cayenne/modeler/plugin/CayenneActionPluginManager.java
    ===================================================================
    --- E:/workspace311/cayenne-java/src/modeler/java/org/objectstyle/cayenne/modeler/plugin/CayenneActionPluginManager.java (revision
    0)
    +++ E:/workspace311/cayenne-java/src/modeler/java/org/objectstyle/cayenne/modeler/plugin/CayenneActionPluginManager.java (revision
    0)
    @@ -0,0 +1,111 @@
    +/* ====================================================================
    + *
    + * The ObjectStyle Group Software License, version 1.1
    + * ObjectStyle Group - http://objectstyle.org/
    + *
    + * Copyright (c) 2006, Andrei (Andrus) Adamchik and individual authors
    + * of the software. All rights reserved.
    + *
    + * Redistribution and use in source and binary forms, with or without
    + * modification, are permitted provided that the following conditions
    + * are met:
    + *
    + * 1. Redistributions of source code must retain the above copyright
    + * notice, this list of conditions and the following disclaimer.
    + *
    + * 2. Redistributions in binary form must reproduce the above copyright
    + * notice, this list of conditions and the following disclaimer in
    + * the documentation and/or other materials provided with the
    + * distribution.
    + *
    + * 3. The end-user documentation included with the redistribution, if any,
    + * must include the following acknowlegement:
    + * "This product includes software developed by independent contributors
    + * and hosted on ObjectStyle Group web site (http://objectstyle.org/)."
    + * Alternately, this acknowlegement may appear in the software itself,
    + * if and wherever such third-party acknowlegements normally appear.
    + *
    + * 4. The names "ObjectStyle Group" and "Cayenne" must not be used to endorse
    + * or promote products derived from this software without prior written
    + * permission. For written permission, email
    + * "andrus at objectstyle dot org".
    + *
    + * 5. Products derived from this software may not be called "ObjectStyle"
    + * or "Cayenne", nor may "ObjectStyle" or "Cayenne" appear in their
    + * names without prior written permission.
    + *
    + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
    + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
    + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    + * DISCLAIMED. IN NO EVENT SHALL THE OBJECTSTYLE GROUP OR
    + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
    + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
    + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
    + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
    + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    + * SUCH DAMAGE.
    + * ====================================================================
    + *
    + * This software consists of voluntary contributions made by many
    + * individuals and hosted on ObjectStyle Group web site. For more
    + * information on the ObjectStyle Group, please see
    + * <http://objectstyle.org/>.
    + */
    +package org.objectstyle.cayenne.modeler.plugin;
    +
    +import java.util.List;
    +
    +import org.apache.log4j.Logger;
    +
    +public class CayenneActionPluginManager {
    +
    + private static final Logger logObj =
    Logger.getLogger(CayenneActionPluginManager.class);
    +
    + private CayenneActionPluginFactory cayenneActionPluginFactory = null;
    + public CayenneActionPluginFactory getCayenneActionPluginFactory()
    + {
    + // TODO: retrieve somehow and allow multiple factories.
    + if (null == cayenneActionPluginFactory)
    + {
    + String pluginName =
    System.getProperty("org.apache.cayenne.modeler.cayenneActionPluginFactory");
    + if (null != pluginName)
    + {
    + try {
    + cayenneActionPluginFactory =
    (CayenneActionPluginFactory)Class.forName(pluginName).newInstance();
    + }
    + catch (InstantiationException e) {
    + logObj.error("InstantiationException error
    instantiating cayenneActionPluginFactory", e);
    + }
    + catch (IllegalAccessException e) {
    + logObj.error("IllegalAccessException error
    instantiating cayenneActionPluginFactory", e);
    + }
    + catch (ClassNotFoundException e) {
    + logObj.error("ClassNotFoundException error
    instantiating cayenneActionPluginFactory", e);
    + }
    + }
    + }
    + return cayenneActionPluginFactory;
    + }
    +
    + private static CayenneActionPluginManager instance = null;
    + public static CayenneActionPluginManager getInstance() {
    + if (null == instance)
    + {
    + instance = new CayenneActionPluginManager();
    + }
    + return instance;
    + }
    +
    + public List getCayenneActionPluginList() {
    + CayenneActionPluginFactory cayenneActionPluginFactory =
    getCayenneActionPluginFactory();
    + if (null != cayenneActionPluginFactory)
    + {
    + return
    getCayenneActionPluginFactory().getCayenneActionPluginList();
    + }
    +
    + return null;
    + }
    +
    +}
    \ No newline at end of file

    Index: E:/workspace311/cayenne-java/src/modeler/java/org/objectstyle/cayenne/modeler/plugin/BaseCayenneActionPlugin.java
    ===================================================================
    --- E:/workspace311/cayenne-java/src/modeler/java/org/objectstyle/cayenne/modeler/plugin/BaseCayenneActionPlugin.java (revision
    0)
    +++ E:/workspace311/cayenne-java/src/modeler/java/org/objectstyle/cayenne/modeler/plugin/BaseCayenneActionPlugin.java (revision
    0)
    @@ -0,0 +1,34 @@
    +package org.objectstyle.cayenne.modeler.plugin;
    +
    +import org.objectstyle.cayenne.modeler.Application;
    +import org.objectstyle.cayenne.modeler.plugin.CayenneActionPlugin;
    +import org.objectstyle.cayenne.modeler.util.CayenneAction;
    +
    +abstract public class BaseCayenneActionPlugin implements CayenneActionPlugin {
    +
    + abstract public String getActionName();
    + abstract public CayenneAction createCayenneAction(Application application);
    +
    + public boolean isSpecialAction() {
    + return false;
    + }
    + public boolean isProjectAction() {
    + return false;
    + }
    + public boolean isDomainAction() {
    + return false;
    + }
    + public boolean isDataMapAction() {
    + return false;
    + }
    + public boolean isObjEntityAction() {
    + return false;
    + }
    + public boolean isDbEntityAction() {
    + return false;
    + }
    + public boolean isProcedureAction() {
    + return false;
    + }
    +
    +}
  • Durchholz, Joachim at Jan 19, 2012 at 5:18 pm

    Oh... you can write extensions to Modeler?
    Is there an official interface for that?
    I don't think this made it into the official code.
    Ah. Pity.
    Unfortunately, it's unlikely that I'll get the time budget to do this.

    Ah well. I think I'll go with the script-from-external-sources route anyway.

    Assuming Cayenne does indeed make it into our project.
    I'm still exploring possibilities... and Hibernate seems to work "well enough" again *sigh*.
    Anyway, this has been digging up interesting details, and maybe given the devs some interesting data points, too, so I hope this all is going to do some good in the end :-)

    Regards,
    Jo
  • Aristedes Maniatis at Jan 18, 2012 at 11:41 pm

    On 19/01/12 2:33 AM, Durchholz, Joachim wrote:


    I see Modeler is one of the major sources of "huh?" moments on the list. It's an additional layer of abstraction between what Cayenne does and what the developer sees, meaning it can introduce problems (and occasionally does); I'd want to get my feet wet with Cayenne without that complication.
    I am not sure it introduces problems. Sure you can edit XML by hand, but modeler is a major convenience.
    1b) Does Cayenne offer a way to check consistency between XML and a database? (I wouldn't object to using Modeler for that limited purpose. That might even be a good way to getting used to Modeler's view of the data model. I guess the answer is "yes", the modeler docs talk about "Validation of created mappings", but it would be nice to confirm I'm not misunderstanding something here.)
    Look at the reverse engineering options in modeler.

    1c) If there's a way to check consistency, are inconsistencies reported in a way that a Cayenne newbie would understand? Such error messages can be difficult to generate, they'd need to detail both the involved RDBMS concepts (tables, fields, lengths, precisions, FKs etc.) and the involved Cayenne concepts (class definitions, associations). And since an error means these are out of sync, the error message would need to be as precise as possible about the nature of the inconsistency, which is no mean feat.
    Mainly you will get runtime errors when you try to fetch or save data. Sometimes they are clear and obvious. Sometimes less so.


    2) How would one assign a "field type" with a field in a Cayenne Pojo?

    With "field type", I mean things like
    123456789012345678901234567890123456789012345678901234567890123456789012
    - Associating textual representation with field contents, such as
    -- shorthands in the database table, Java enums internally,
    longer texts on display
    -- or maybe shorthands in the database table, Java Strings internally,
    longer texts on display
    Cayenne has very nice support for enums. You can map against enums directly in the model and then define how those enums will be written to the database. This works well.

    - What Swing controls to use for displaying this data
    ("Renderer" in Swing terminology)
    - What Swing controls to use for editing this data
    ("Editor" in Swing terminology)
    Cayenne isn't going to help you with building your UI. Yes, you can fire events in Swing to fetch and save data back to the entity objects, but you need to wire that all up yourself and wrap it with a controller that knows how to deal with Cayenne contexts.
    - Validation info: valid ranges; probably a Java interface with
    implementations that may or may not use RDBMS length/precision info
    Anything you can validate in Java code can be added to the entity classes.
    - Possibly association with more than one field
    (date/time in two fields but merged into one Java property)
    Sure. You can write any of this easily.

    (or still two Java properties, but validation etc. spans all of them)
    No problem. Validation can easily do this, since you are validating the whole object, not each attribute.

    I see various possible approaches:

    2a) The traditional Cayenne approach. Make the entity class a superclass, the business class a subclass. Entity class properties would have private members and protected getters/setters, the business class would then use a FieldType object to delegate public getters/setters to the protected getters/setters. (FieldType objects would be static and accept entity objects as parameters, so memory bloat isn't an issue. I'm using a similar construction in my current Hibernate infrastructure.)
    I'm a bit worried about the amount of boilerplate needed in the business class. In particular for the trivial cases where the DB field is simply handed through to the business logic (e.g. address fields where the end user should be able to put in pretty anything they choose as long as it fits the database field).
    What boilerplate? That class will be almost empty. And as John says, you can customise the velocity templates any way you like.

    2b) Use delegation instead of subclassing. The issues are essentially the same, except the getters/setters of the entity class wouldn't have to be package-private or public instead of protected.
    Are there other issues that I should be aware of?

    2c) Since I'm not too dependent on Modeler, I might merge entity and business class.
    I'm not sure that such a merge has any advantages; does anybody have seen this tried? Stories of failure and success equally interesting here.
    I have to admit I don't expect success, merging abstractions usually doesn't work well in the long term; losing the option to use Modeler's code generation later when we're more confident in it is a strong point agains that route, too. Still, I'd like to know how much water this assessment holds.
    You are making this hard for yourself without any obvious gain.

    2d) Anything I haven't thought of. Different ways to use Java reflection, a Modeler option I'm not aware of that does all these things out of the box, whatever.


    3) How do I do cascading?

    I have seen some mention of this in the docs but haven't found a comprehensive description.
    Do you mean cascading of deletes across relations? Or something else? Perhaps you want to play with the event listeners in the modeler. That might be what you are after.


    Cheers
    Ari



    --
    -------------------------->
    Aristedes Maniatis
    GPG fingerprint CBFB 84B4 738D 4E87 5E5C 5EFA EF6A 7D2E 3E49 102A
  • Tomas Stenlund at Jan 19, 2012 at 6:37 am
    On 01/18/2012 04:33 PM, Durchholz, Joachim wrote:

    Well I just do that, answer a few of the questions:
    ...


    2) How would one assign a "field type" with a field in a Cayenne Pojo?

    With "field type", I mean things like
    123456789012345678901234567890123456789012345678901234567890123456789012
    - Associating textual representation with field contents, such as
    -- shorthands in the database table, Java enums internally,
    longer texts on display
    -- or maybe shorthands in the database table, Java Strings internally,
    longer texts on display
    - What Swing controls to use for displaying this data
    ("Renderer" in Swing terminology)
    - What Swing controls to use for editing this data
    ("Editor" in Swing terminology)
    - Validation info: valid ranges; probably a Java interface with
    implementations that may or may not use RDBMS length/precision info
    - Possibly association with more than one field
    (date/time in two fields but merged into one Java property)
    (or still two Java properties, but validation etc. spans all of them)

    I see various possible approaches:

    2a) The traditional Cayenne approach. Make the entity class a superclass, the business class a subclass. Entity class properties would have private members and protected getters/setters, the business class would then use a FieldType object to delegate public getters/setters to the protected getters/setters. (FieldType objects would be static and accept entity objects as parameters, so memory bloat isn't an issue. I'm using a similar construction in my current Hibernate infrastructure.)
    I'm a bit worried about the amount of boilerplate needed in the business class. In particular for the trivial cases where the DB field is simply handed through to the business logic (e.g. address fields where the end user should be able to put in pretty anything they choose as long as it fits the database field).

    2b) Use delegation instead of subclassing. The issues are essentially the same, except the getters/setters of the entity class wouldn't have to be package-private or public instead of protected.
    Are there other issues that I should be aware of?

    2c) Since I'm not too dependent on Modeler, I might merge entity and business class.
    I'm not sure that such a merge has any advantages; does anybody have seen this tried? Stories of failure and success equally interesting here.
    I have to admit I don't expect success, merging abstractions usually doesn't work well in the long term; losing the option to use Modeler's code generation later when we're more confident in it is a strong point agains that route, too. Still, I'd like to know how much water this assessment holds.

    2d) Anything I haven't thought of. Different ways to use Java reflection, a Modeler option I'm not aware of that does all these things out of the box, whatever.
    I have developed an application for cross country skiing competitions,
    time keeping, handling skiers, result service and so on using Cayenne.
    What I have discovered when it comes to UI I just stuck with the
    generated Entity class and added new getters/setters to fit my GUI
    whenever needed. Now in retrospect it looks somewhat ugly because my GUI
    layout now "pollutes" the Entity class. Either way it works, it is fast
    and works great with Cayenne instead of maybe going with a nicer design
    with inheritance one additional level as suggested in 2a (actually the
    cayenne getters/setters would be visible as well). It gives me both
    benefits and drawbacks. It is not my proudest design, but then again I
    does the job and I learned to use Cayenne and the GUI-frameowork at the
    same time.

    Now something completely different, 2d.

    For the GUI part, I'n not using Swing. I use Apache Pivot which I think
    works great with Cayenne. It binds the controls to the getters/settes
    directly into a Pojo (e.g. the cayenne entity object) and also have
    support for datamapping, which allows you to move the data conversion
    from the cayenne entity more towards the GUI instead (which I would like
    to have it, instead of in the entities). Your "own" GUI-code is minimal
    in each dialog/window. I think this is a quite a nice approach that you
    could look at. But then again, this is GUI and not Cayenne.

    Cheers,

    Tomas
  • Durchholz, Joachim at Jan 19, 2012 at 11:58 am
    Thanks for the answer.
    I have developed an application for cross country skiing
    competitions, time keeping, handling skiers, result service
    and so on using Cayenne.
    What I have discovered when it comes to UI I just stuck with
    the generated Entity class and added new getters/setters to
    fit my GUI whenever needed.
    Now in retrospect it looks somewhat ugly because my GUI
    layout now "pollutes" the Entity class. [...]
    It is not my proudest design, but then again I does the job
    I can see that :-)

    Actually, our current code is in a state that isn't THAT different, but we're getting more and more into maintenance and adapation to different frontends (currently: migrating the stuff from desktop app to webservice). Separation will soon be a necessity.
    For the GUI part, I'n not using Swing. I use Apache Pivot
    which I think works great with Cayenne.
    Wow. Pivot looks like a very interesting framework.
    I wish I had noticed its release; it covers most if not all hard problems I'm facing right now.

    Regards,
    Jo
  • Erlend Birkenes at Jan 19, 2012 at 1:25 pm
    2012/1/18 Durchholz, Joachim <Joachim.Durchholz@hennig-fahrzeugteile.de>
    1) Does anybody have concrete advice about using Cayenne without Modeler?

    Background:
    I see Modeler is one of the major sources of "huh?" moments on the list.
    It's an additional layer of abstraction between what Cayenne does and what
    the developer sees, meaning it can introduce problems (and occasionally
    does); I'd want to get my feet wet with Cayenne without that complication.
    I also see it's the one part that you actually can avoid using - the XML
    can be edited by hand.
    I'm pretty new at this, but here are our experiences with this so far:

    The modeler is pretty nice to work with if you don't have that many and/or
    large entities, or don't need much customization, but point and click gets
    old pretty fast.

    We have written a simple generator to generate the .map.xml file that the
    Modeler produces. It's just a simple Java class (<400 lines) that writes
    strings to the file. Writing a generator for this is very simple since
    everything is in one file and you can just add all the relationships at the
    bottom, no need to go back and forth between entities and stuff like that.

    The reason we did this is because we maintain our own database metadata
    stored in the database and we wanted to use that. (We also have almost 300
    Entities, so modifying them manually in the Modeler was out of the
    question.) So it was very simple for us to get all we needed from there. I
    guess it's relatively simple to get this from JDBC DatabaseMetadata and use
    that instead, or define it some other way.

    After doing that I'm glad we did, as it gives us MUCH more control over the
    whole thing. It's very simple to manipulate things, and lets us do things
    like add flattened attributes on all ObjEntities so they all implement a
    common interface, something that is very cumbersome in the Modeler. It's
    much easier to get stuff exactly how we want them when we can program them
    (after all we are programmers, not mouse clickers, right..?)

    As I said, I really like the map.xml file format, which just lists the
    db-entities, obj-entities, db-relationships and obj-relationships. Very
    easy to generate and manipulate.
    It is very poorly documented, but easy enough to figure out based on the
    Schema and by experimenting in the Modeler and see what it produces.

    When we have the map.xml we just use the cgen ant task to generate the
    classes.

    So you don't have to use the modeler, but I wouldn't recommend hand-editing.


    -Erlend
  • Durchholz, Joachim at Jan 19, 2012 at 1:54 pm

    Writing a generator for this is very simple since everything
    is in one file
    Oh. Is that one XML for all entities?
    Or am I misunderstanding something here?
    I'd really prefer to have one XML per table.
    The reason we did this is because we maintain our own database
    metadata stored in the database and we wanted to use that.
    We'll have to go down a similar route. We'll have to interact with an ERP system that declares all fields as NUMBER, and keeps metadata about actual valid ranges, precision and scale partly in tables, partly in text files.
    It's going to be fun, of the non-fun type.
    (We also have almost 300 Entities, so modifying them manually
    in the Modeler was out of the question.)
    Hmm... that's not a large number.
    Seems like Modeler doesn't scale well enough for even medium-sized projects.

    We're at just ~50 tables here, so Modeler might still work for us, but I guess we better look for something textfile-based. Either direct XML editing or some simple source from which we can generate the XML.
    So it was very simple for us to get all we needed from there.
    I guess it's relatively simple to get this from JDBC
    DatabaseMetadata and use that instead,
    Depends. The metadata is defined as a query result, which a very handwavy explanation what to find in which column.
    With the consequence that every RDBMS fills the columns with subtly different kinds of information.
    Plus, at least one major vendor (Oracle) is known to return bogus data for many constellations. You need to know these constellations and infer them from the parameter data that you get.

    More fun of the non-fun type ;-)

    That said, there are reliable ways to get that kind of data, even from Oracle. You just don't want to use the DatabaseMetadata API in JDBC, but something vendor-specific. If you need to get something to work quickly (as opposed to getting it done once and for all), you can manage; the task becomes even easier if the tables have all been defined along the same set of conventions, so you don't hit each and every weird constellation of misreported metadata.
    or define it some other way.
    This. It seems the ability to merge metadata from multiple sources is essential.
    I find myself wanting to specify metadata beyond what the database can give me. Such as enums and their associations with the strings encoded in the database. Or what kind of formatting to use for a NUMBER - we want different formats depending on whether the number is an ID (no separators), a quantity (decimal and fractional separators), or a monetary amount (as quantity but also a currency symbol). We have DATE fields where 9999-12-31 was defined to be roughly equivalent to NULL, so the display rules for that field are different from ordinary DATE fields. And so on and so on.
    After doing that I'm glad we did, as it gives us MUCH
    more control over the whole thing. It's very simple
    to manipulate things, and lets us do things like add
    flattened attributes on all ObjEntities so they all
    implement a common interface, Sweet :-)
    something that is very cumbersome in the Modeler. It's
    much easier to get stuff exactly how we want them when
    we can program them (after all we are programmers, not
    mouse clickers, right..?)
    Hehe, right :-)
    As I said, I really like the map.xml file format, which
    just lists the db-entities, obj-entities, db-relationships
    and obj-relationships. Very easy to generate and manipulate.
    It is very poorly documented, but easy enough to figure out
    based on the Schema and by experimenting in the Modeler and
    see what it produces.
    Good to know.
    Thanks.
    When we have the map.xml we just use the cgen ant task to
    generate the classes.
    Huh. Somehow I never made it to the page documenting the Ant tasks. Probably because I never properly realized their significance.
    Thanks for pointing that out.
    So you don't have to use the modeler, but I wouldn't
    recommend hand-editing.
    Okay, I'll keep that in mind.

    Regards,
    Jo
  • Erlend Birkenes at Jan 19, 2012 at 2:19 pm
    2012/1/19 Durchholz, Joachim <Joachim.Durchholz@hennig-fahrzeugteile.de>
    Writing a generator for this is very simple since everything
    is in one file
    Oh. Is that one XML for all entities?
    Or am I misunderstanding something here?
    I'd really prefer to have one XML per table.
    Yeah, it's one big file. In our case it's 1.4MB and 17k lines. So I'm not
    hand-editing that! ;-)

    If you generate it yourself i'm sure it's easy to keep each entity in it's
    own file for easier editing and then just build the map.xml from those. The
    fact that it is a almost flat xml file is good for this. Actually you could
    probably use xml !ENTITY to do it directly, but I haven't tried.


    -Erlend
  • Aristedes Maniatis at Jan 20, 2012 at 2:34 am

    On 20/01/12 12:24 AM, Erlend Birkenes wrote:

    As I said, I really like the map.xml file format, which just lists the
    db-entities, obj-entities, db-relationships and obj-relationships. Very
    easy to generate and manipulate.
    It is very poorly documented, but easy enough to figure out based on the
    Schema and by experimenting in the Modeler and see what it produces.
    Not perfect, but this helps...

    http://cayenne.apache.org/schema/3.0/indexList.html

    Happy to accept any help with getting better docs into the schema XSD.


    Ari


    --
    -------------------------->
    Aristedes Maniatis
    GPG fingerprint CBFB 84B4 738D 4E87 5E5C 5EFA EF6A 7D2E 3E49 102A
  • Erlend Birkenes at Jan 20, 2012 at 9:22 am
    2012/1/20 Aristedes Maniatis <ari@maniatis.org>
    Not perfect, but this helps...

    http://cayenne.apache.org/**schema/3.0/indexList.html<http://cayenne.apache.org/schema/3.0/indexList.html>

    Happy to accept any help with getting better docs into the schema XSD.
    Thanks, I knew about that and it was very useful. It's not always obvious
    what the various tags are for, so it could use more descriptions. I
    generally had to do things in the Modeler and look at the resulting XML to
    figure out how to do things correctly. I have checked out the source, so
    I'll see if I can write some docs when I have some time.

    One of the things I wondered about: what is the point of the
    attribute-override? I see the Modeler uses it for flattened attributes, so
    I do too, but the obj-attribute seems to already say the exact same thing
    so I don't see the point.

    Your link is broken btw, it just shows the index and not the content. This
    is the correct URL:

    http://cayenne.apache.org/schema/3.0/modelMap.html


    -Erlend
  • Aristedes Maniatis at Jan 20, 2012 at 10:08 am

    On 20/01/12 8:21 PM, Erlend Birkenes wrote:
    2012/1/20 Aristedes Maniatis<ari@maniatis.org>
    Not perfect, but this helps...

    http://cayenne.apache.org/**schema/3.0/indexList.html<http://cayenne.apache.org/schema/3.0/indexList.html>

    Happy to accept any help with getting better docs into the schema XSD.
    Thanks, I knew about that and it was very useful. It's not always obvious
    what the various tags are for, so it could use more descriptions. I
    generally had to do things in the Modeler and look at the resulting XML to
    figure out how to do things correctly. I have checked out the source, so
    I'll see if I can write some docs when I have some time.
    Great. I think it would be terrifically useful to extract docs from javadocs and anywhere else we can, to insert into the XSD file. Then I can regenerate the docs and we'll get much more informative web pages.

    One of the things I wondered about: what is the point of the
    attribute-override? I see the Modeler uses it for flattened attributes, so
    I do too, but the obj-attribute seems to already say the exact same thing
    so I don't see the point.
    I am not sure. I generated the html docs and the XSD, but I didn't always understand some of the more obscure bits. Andrus will know.

    Your link is broken btw, it just shows the index and not the content. This
    is the correct URL:

    http://cayenne.apache.org/schema/3.0/modelMap.html
    Yes, that's better.


    It is also worth noting that Cayenne modeler isn't validating its output or input against the schema right now. We didn't want to enable that and break XML files which work, but which did not meet the schema exactly (for example, XSD is very particular about the order of attributes).


    Ari



    --
    -------------------------->
    Aristedes Maniatis
    GPG fingerprint CBFB 84B4 738D 4E87 5E5C 5EFA EF6A 7D2E 3E49 102A
  • Durchholz, Joachim at Jan 20, 2012 at 10:14 am

    It is also worth noting that Cayenne modeler isn't validating its
    output or input against the schema right now. We didn't want to
    enable that and break XML files which work, but which did not meet
    the schema exactly (for example, XSD is very particular about the
    order of attributes).
    I see a potential for Modeler introducing errors which might make other tools choke.
    Is this a problem in practice?

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
groupuser @
categoriescayenne
postedJan 18, '12 at 3:34p
activeJan 20, '12 at 10:14a
posts17
users6
websitecayenne.apache.org

People

Translate

site design / logo © 2022 Grokbase