FAQ
Hi all,

Please point me to the previous message if this has already been
addressed.. I did a quick search, but couldn't find anything that looked
directly relevant.

Anyway: I have been maintaining the SQL Objectstore (jdbc) for
Apache Isis (currently in the incubator), and would like to know if
Cayenne can be used completely "in the background", with no user
integration (i.e. no need to run the configuration tool / modeller / etc).

Isis is a complete framework solution for developing and deploying
POJO / domain objects, and provides hooks for persistence tasks.
For example, the metamodel context provide:
public ObjectInstantiator getObjectInstantiator();
public ObjectDirtier getObjectDirtier();
public ObjectPersistor getObjectPersistor();

where, for example:
public interface ObjectInstantiator extends Injectable {
/**
* Provided by the <tt>ObjectFactory</tt> when used by framework.
*
* <p>
* Called by {@link ObjectSpecificationDefault}.
*/
Object instantiate(Class<?> cls) throws
ObjectInstantiationException;
}

Isis requires no annotations, etc, to support persistence, which is
taken care of via introspection. Some hints can be provided to the
objectstore via the "isis.properties" file, if required.

So, I would like to know how difficult would it be to "just" hook Cayenne
into the object "create", "find" and "update" methods of Isis, and let
Cayenne take care of the ORM / persistence?

Taking a quick browse through the examples, I don't see where I
configure the database connection, for example.

Regards,
Kevin

Search Discussions

  • John Huss at Dec 6, 2011 at 3:05 pm
    For the DB connection, if you're using 3.0 there is some info here:
    https://cwiki.apache.org/CAY/setting-database-connection.html

    For 3.1, you can use a properties file to store the value and load them in
    a custom DI module by doing something like:

    public class PropertiesModule implements Module {
    public void configure(Binder binder) {
    MapBuilder<Object> mapBuilder =
    binder.bindMap(DefaultRuntimeProperties.PROPERTIES_MAP);
    Properties props = ... load properties from a file
    for (Object keyObj : props.keySet()) {
    String key = (String)keyObj;
    mapBuilder.put(key, props.get(key));
    }
    }
    }

    Where the properties are set like this:
    cayenne.jdbc.driver.MyDomain.MyNode=org.postgresql.Driver
    cayenne.jdbc.url.MyDomain.MyNode=jdbc:postgresql://localhost/mydb
    cayenne.jdbc.username.MyDomain.MyNode=postgres
    cayenne.jdbc.password.MyDomain.MyNode=*******
    cayenne.min.connections.MyDomain.MyNode=1
    cayenne.max.connections.MyDomain.MyNode=1

    You can use Cayenne without running the modeler, but it would be rather
    cumbersome since you would have to create the whole model programmatically
    at runtime each time. And normally you would generate custom classes for
    your Entities (objects), but without having a pre-existing model you would
    just have to use CayenneDataObject directly which will force you to access
    values by name instead of via getters and setters.
    If those requirements are acceptable, then it could work.

    The "update" method might be tricker. Cayenne saves all changes to the
    entire object graph at once; you can't just save one object, you save all
    changes to the related objects that are loaded and modified. If this is
    different than the "update" concept in Isis then it may be a problem.

    John
    On Tue, Dec 6, 2011 at 12:59 AM, Kevin Meyer - KMZ wrote:

    Hi all,

    Please point me to the previous message if this has already been
    addressed.. I did a quick search, but couldn't find anything that looked
    directly relevant.

    Anyway: I have been maintaining the SQL Objectstore (jdbc) for
    Apache Isis (currently in the incubator), and would like to know if
    Cayenne can be used completely "in the background", with no user
    integration (i.e. no need to run the configuration tool / modeller / etc).

    Isis is a complete framework solution for developing and deploying
    POJO / domain objects, and provides hooks for persistence tasks.
    For example, the metamodel context provide:
    public ObjectInstantiator getObjectInstantiator();
    public ObjectDirtier getObjectDirtier();
    public ObjectPersistor getObjectPersistor();

    where, for example:
    public interface ObjectInstantiator extends Injectable {
    /**
    * Provided by the <tt>ObjectFactory</tt> when used by framework.
    *
    * <p>
    * Called by {@link ObjectSpecificationDefault}.
    */
    Object instantiate(Class<?> cls) throws
    ObjectInstantiationException;
    }

    Isis requires no annotations, etc, to support persistence, which is
    taken care of via introspection. Some hints can be provided to the
    objectstore via the "isis.properties" file, if required.

    So, I would like to know how difficult would it be to "just" hook Cayenne
    into the object "create", "find" and "update" methods of Isis, and let
    Cayenne take care of the ORM / persistence?

    Taking a quick browse through the examples, I don't see where I
    configure the database connection, for example.

    Regards,
    Kevin

  • Kevin Meyer - KMZ at Dec 7, 2011 at 8:12 am
    Dear John,

    Thanks for your response.
    On 6 Dec 2011 at 9:04, John Huss wrote:

    You can use Cayenne without running the modeler, but it would be rather
    cumbersome since you would have to create the whole model programmatically
    at runtime each time.
    So Cayenne does not introspect the POJOs?

    I suppose I can work with having to run a config tool every now and
    then, as design changes need to be handled.
    And normally you would generate custom classes for your Entities
    (objects), but without having a pre-existing model you would just
    have to use CayenneDataObject directly which will force you to
    access values by name instead of via getters and setters. If those
    requirements are acceptable, then it could work.
    Isis does not generate code - it uses the users POJOs as is, with extra
    methods or annotations to affect behaviour, visibility etc.

    I was hoping that I could merely require that Cayenne-managed
    POJOs extend a Cayenne-compatible base class, and no more, and
    that only getXXX/setXXX methods would be used to map XXX into the
    ORM. In Isis, a getXXX-only implies a read-only property, and setYYY
    only is for injecting services. Neither of which are passed to the Isis
    ORM.
    The "update" method might be tricker. Cayenne saves all changes to the
    entire object graph at once; you can't just save one object, you save all
    changes to the related objects that are loaded and modified. If this is
    different than the "update" concept in Isis then it may be a problem.
    No problem - Isis does something similar. If an object is transient, all
    properties are "walked" and persisted. But objects in the entire graph
    are not persisted if they have not changed.

    Regards,
    Kevin
  • John Huss at Dec 8, 2011 at 3:11 pm

    On Wed, Dec 7, 2011 at 2:11 AM, Kevin Meyer - KMZ wrote:

    Dear John,

    Thanks for your response.
    On 6 Dec 2011 at 9:04, John Huss wrote:

    You can use Cayenne without running the modeler, but it would be rather
    cumbersome since you would have to create the whole model
    programmatically
    at runtime each time.
    So Cayenne does not introspect the POJOs?

    I suppose I can work with having to run a config tool every now and
    then, as design changes need to be handled.
    And normally you would generate custom classes for your Entities
    (objects), but without having a pre-existing model you would just
    have to use CayenneDataObject directly which will force you to
    access values by name instead of via getters and setters. If those
    requirements are acceptable, then it could work.
    Isis does not generate code - it uses the users POJOs as is, with extra
    methods or annotations to affect behaviour, visibility etc.

    I was hoping that I could merely require that Cayenne-managed
    POJOs extend a Cayenne-compatible base class, and no more, and
    that only getXXX/setXXX methods would be used to map XXX into the
    ORM. In Isis, a getXXX-only implies a read-only property, and setYYY
    only is for injecting services. Neither of which are passed to the Isis
    ORM.
    You could probably reverse-engineer a model by introspecting specific
    classes, but you would have to make assumptions about the database mapping
    information (jdbc type, width, scale precision) unless that is available
    via annotations in your classes.
    The "update" method might be tricker. Cayenne saves all changes to the
    entire object graph at once; you can't just save one object, you save all
    changes to the related objects that are loaded and modified. If this is
    different than the "update" concept in Isis then it may be a problem.
    No problem - Isis does something similar. If an object is transient, all
    properties are "walked" and persisted. But objects in the entire graph
    are not persisted if they have not changed.

    Regards,
    Kevin
  • Kevin Meyer - KMZ at Dec 9, 2011 at 4:58 pm
    Indeed - The Isis SQL objectstore itself works by making assumptions
    about jdbc type, etc. The defaults can be altered at runtime, but most
    work out-of-the-box against MySQL, PostgreSQL and HSQLDB.

    On 8 Dec 2011 at 9:10, John Huss wrote:

    I was hoping that I could merely require that Cayenne-managed
    POJOs extend a Cayenne-compatible base class, and no more, and
    that only getXXX/setXXX methods would be used to map XXX into the
    ORM. In Isis, a getXXX-only implies a read-only property, and setYYY
    only is for injecting services. Neither of which are passed to the Isis
    ORM.
    You could probably reverse-engineer a model by introspecting specific
    classes, but you would have to make assumptions about the database mapping
    information (jdbc type, width, scale precision) unless that is available
    via annotations in your classes.
  • Andrus Adamchik at Dec 9, 2011 at 2:19 am
    Hi Kevin,

    I should say that Cayenne is uniquely suited for creating persistent stack and mapping at runtime, as there's no class enhancement involved. POJO's being subclasses of CayenneDataObject, with set/get implemented the way we do them in Cayenne is the only hard requirement. From there, as John has mentioned, you make some assumptions. The biggest assumption is that you control the DB and there's no chance of a legacy schema that you'd have to support (in which case you will need to create Cayenne mapping by hand to reconcile column naming and type differences between Java and DB).

    Implementation (assuming Cayenne 3.1) may be encapsulated in a custom Cayenne DI module. We are still in the process of writing the docs for 3.1, but most DI features are well documented in this otherwise empty PDF:

    http://people.apache.org/~aadamchik/misc/cayenne-guide-08302011.pdf

    In the custom module define DataDomain loading services to reverse-engineer the POJOs instead of loading mapping from XML. This is the biggest task, requiring some understanding of Cayenne APIs. Feel free to ask here if you get stuck with anything. Also map SchemaUpdateStrategy to CreateIfNoSchemaStrategy that will create a DB schema based on your mapping.

    This should be it at the high level, but of course you'll need to write some code here. I used to implement a similar task - going from reverse-engineered DB to a runtime mapping of generic Java classes, and that worked pretty well.

    Good luck, and let us know how this works - maybe some of these new factories that you develop could be of general use to Cayenne users as well as ISIS users.

    Andrus

    On Dec 5, 2011, at 8:59 PM, Kevin Meyer - KMZ wrote:

    Hi all,

    Please point me to the previous message if this has already been
    addressed.. I did a quick search, but couldn't find anything that looked
    directly relevant.

    Anyway: I have been maintaining the SQL Objectstore (jdbc) for
    Apache Isis (currently in the incubator), and would like to know if
    Cayenne can be used completely "in the background", with no user
    integration (i.e. no need to run the configuration tool / modeller / etc).

    Isis is a complete framework solution for developing and deploying
    POJO / domain objects, and provides hooks for persistence tasks.
    For example, the metamodel context provide:
    public ObjectInstantiator getObjectInstantiator();
    public ObjectDirtier getObjectDirtier();
    public ObjectPersistor getObjectPersistor();

    where, for example:
    public interface ObjectInstantiator extends Injectable {
    /**
    * Provided by the <tt>ObjectFactory</tt> when used by framework.
    *
    * <p>
    * Called by {@link ObjectSpecificationDefault}.
    */
    Object instantiate(Class<?> cls) throws
    ObjectInstantiationException;
    }

    Isis requires no annotations, etc, to support persistence, which is
    taken care of via introspection. Some hints can be provided to the
    objectstore via the "isis.properties" file, if required.

    So, I would like to know how difficult would it be to "just" hook Cayenne
    into the object "create", "find" and "update" methods of Isis, and let
    Cayenne take care of the ORM / persistence?

    Taking a quick browse through the examples, I don't see where I
    configure the database connection, for example.

    Regards,
    Kevin

  • Kevin Meyer - KMZ at Dec 9, 2011 at 4:58 pm
    Hi Andrus,

    Thanks for the details.

    I had an initial read through of the cayenne-guide-08302011.pdf, but
    I'm not sure what I'm looking for.

    For the most part, I *do* assume that I have total control over the DB,
    with no legacy support. Or at least, nothing beyond choosing property
    names to suit matching database table column names and similar.


    I still don't have a good idea how Cayenne works - how it's started, etc.
    More reading required.

    At some point, I am supposing I'll want to know: How do I specify that
    property X of class Y represents a value (e.g. int), and that property A
    represents an instance of class Z.

    e.g. (where there's a get, assume there's a set)

    class Customer extends CayenneDataObject {

    public int getNumber(){...}

    public Address getAddress(){...}

    }

    The Isis internals introspects Customer and creates various classes
    that either represent the *definition* of Customer, or provide access to
    an actual instance.

    The object store uses this information to support creating tables and
    mappers (either value mappers or reference mappers).

    This is where I expect to I need to tell Cayenne what user domain
    objects exist (and need to be persisted), what value properties they
    have, and what reference properties (pointing to other user domain
    objects).

    The subtleties may come into handling polymorphism, etc., but I've
    gone through this exercise with Isis.


    I've been given a heads-up on how to create a new runtime context for
    Isis that will use Cayenne - when I get to the point that I need to persist
    an object, that's when I need to know more about setting up Cayenne
    programmatically.

    Regards,
    Kevin

    On 8 Dec 2011 at 16:18, Andrus Adamchik wrote:

    Hi Kevin,

    I should say that Cayenne is uniquely suited for creating persistent
    stack and mapping at runtime, as there's no class enhancement
    involved. POJO's being subclasses of CayenneDataObject, with set/get
    implemented the way we do them in Cayenne is the only hard
    requirement. From there, as John has mentioned, you make some
    assumptions. The biggest assumption is that you control the DB and
    there's no chance of a legacy schema that you'd have to support...

    Implementation (assuming Cayenne 3.1) may be encapsulated in a
    custom Cayenne DI module. We are still in the process of writing the
    docs for 3.1, but most DI features are well documented in this
    otherwise empty PDF:

    http://people.apache.org/~aadamchik/misc/cayenne-guide-08302011.pdf

    In the custom module define DataDomain loading services to
    reverse-engineer the POJOs instead of loading mapping from XML. This
    is the biggest task, requiring some understanding of Cayenne APIs.
    Feel free to ask here if you get stuck with anything. Also map
    SchemaUpdateStrategy to CreateIfNoSchemaStrategy that will create a
    DB schema based on your mapping.

    This should be it at the high level, but of course you'll need to
    write some code here. I used to implement a similar task - going
    from reverse-engineered DB to a runtime mapping of generic Java
    classes, and that worked pretty well.

    Good luck, and let us know how this works - maybe some of these new
    factories that you develop could be of general use to Cayenne users
    as well as ISIS users.

    Andrus
  • Andrus Adamchik at Dec 10, 2011 at 5:38 am

    At some point, I am supposing I'll want to know: How do I specify that
    property X of class Y represents a value (e.g. int), and that property A
    represents an instance of class Z.
    Given a finite predefined set of "persistent" classes, it shouldn't be that hard to tell the 2 types of properties apart from each other. Does Isis know all the classes it will be working with upfront, or is it lazily introspecting them one at a time as they are accessed by the app?

    class Customer extends CayenneDataObject {

    public int getNumber(){...}

    public Address getAddress(){...}

    }
    BTW, take a note of how typical getters/setters are implemented in CayenneDataObject subclasses (an example from our unit tests). Hope that's ok in the Isis environment:

    * Simple properties:

    public void setArtistName(String artistName) {
    writeProperty("artistName", artistName);
    }
    public String getArtistName() {
    return (String)readProperty("artistName");
    }

    * To-one relationships:

    public void setToArtist(org.apache.cayenne.testdo.testmap.Artist toArtist) {
    setToOneTarget("toArtist", toArtist, true);
    }

    public org.apache.cayenne.testdo.testmap.Artist getToArtist() {
    return (org.apache.cayenne.testdo.testmap.Artist)readProperty("toArtist");
    }

    * To-many relationships

    public void addToArtistExhibitArray(ArtistExhibit obj) {
    addToManyTarget("artistExhibitArray", obj, true);
    }
    public void removeFromArtistExhibitArray(ArtistExhibit obj) {
    removeToManyTarget("artistExhibitArray", obj, true);
    }
    @SuppressWarnings("unchecked")
    public List<ArtistExhibit> getArtistExhibitArray() {
    return (List<ArtistExhibit>)readProperty("artistExhibitArray");
    }

    Andrus

    On Dec 9, 2011, at 6:58 AM, Kevin Meyer - KMZ wrote:

    Hi Andrus,

    Thanks for the details.

    I had an initial read through of the cayenne-guide-08302011.pdf, but
    I'm not sure what I'm looking for.

    For the most part, I *do* assume that I have total control over the DB,
    with no legacy support. Or at least, nothing beyond choosing property
    names to suit matching database table column names and similar.


    I still don't have a good idea how Cayenne works - how it's started, etc.
    More reading required.

    At some point, I am supposing I'll want to know: How do I specify that
    property X of class Y represents a value (e.g. int), and that property A
    represents an instance of class Z.

    e.g. (where there's a get, assume there's a set)

    class Customer extends CayenneDataObject {

    public int getNumber(){...}

    public Address getAddress(){...}

    }

    The Isis internals introspects Customer and creates various classes
    that either represent the *definition* of Customer, or provide access to
    an actual instance.

    The object store uses this information to support creating tables and
    mappers (either value mappers or reference mappers).

    This is where I expect to I need to tell Cayenne what user domain
    objects exist (and need to be persisted), what value properties they
    have, and what reference properties (pointing to other user domain
    objects).

    The subtleties may come into handling polymorphism, etc., but I've
    gone through this exercise with Isis.


    I've been given a heads-up on how to create a new runtime context for
    Isis that will use Cayenne - when I get to the point that I need to persist
    an object, that's when I need to know more about setting up Cayenne
    programmatically.

    Regards,
    Kevin

    On 8 Dec 2011 at 16:18, Andrus Adamchik wrote:

    Hi Kevin,

    I should say that Cayenne is uniquely suited for creating persistent
    stack and mapping at runtime, as there's no class enhancement
    involved. POJO's being subclasses of CayenneDataObject, with set/get
    implemented the way we do them in Cayenne is the only hard
    requirement. From there, as John has mentioned, you make some
    assumptions. The biggest assumption is that you control the DB and
    there's no chance of a legacy schema that you'd have to support...

    Implementation (assuming Cayenne 3.1) may be encapsulated in a
    custom Cayenne DI module. We are still in the process of writing the
    docs for 3.1, but most DI features are well documented in this
    otherwise empty PDF:

    http://people.apache.org/~aadamchik/misc/cayenne-guide-08302011.pdf

    In the custom module define DataDomain loading services to
    reverse-engineer the POJOs instead of loading mapping from XML. This
    is the biggest task, requiring some understanding of Cayenne APIs.
    Feel free to ask here if you get stuck with anything. Also map
    SchemaUpdateStrategy to CreateIfNoSchemaStrategy that will create a
    DB schema based on your mapping.

    This should be it at the high level, but of course you'll need to
    write some code here. I used to implement a similar task - going
    from reverse-engineered DB to a runtime mapping of generic Java
    classes, and that worked pretty well.

    Good luck, and let us know how this works - maybe some of these new
    factories that you develop could be of general use to Cayenne users
    as well as ISIS users.

    Andrus
  • Kevin Meyer - KMZ at Dec 10, 2011 at 8:21 pm

    On 8 Dec 2011 at 16:18, Andrus Adamchik wrote:


    In the custom module define DataDomain loading services to
    reverse-engineer the POJOs instead of loading mapping from XML. This
    is the biggest task, requiring some understanding of Cayenne APIs.
    Feel free to ask here if you get stuck with anything. Also map
    SchemaUpdateStrategy to CreateIfNoSchemaStrategy that will create a
    DB schema based on your mapping.
    Ok!

    I've decided to first try re-implementing a new Isis ObjectStore (which
    has a bespoke Isis Persistence API) before writing a whole new Isis
    Context which is independent of the Persistence API.

    Anyway.

    I now have my empty project, Isis has been told about a new
    ObjectStore (CayenneObjectStore), and in the
    CayenneObjectStore#open() method, I have created a runtime and a
    context. I also have a custom Module to inject my helpers.

    Of course, when I try create an object:
    Object o = context.newObject(persistentClass);
    I get an exception of:
    Class is not mapped with Cayenne: isis.persistor.SimpleClassA
    which is to be expected.

    So!

    I expect I need to provide a custom binder for EntityResolver?

    I'm trying:
    binder.bind(EntityResolver.class).toInstance(
    new IsisEntityResolver());

    in my custom module, but its not being picked up in the DataContext.

    But I can inject it manually:
    DataContext dc = (DataContext) context;
    dc.setEntityResolver(new IsisEntityResolver());

    Nevermind.

    What are the basics of defining DataDomain loading services to
    reverse-engineer the POJOs ?

    I already have the list of domain entities and their properties (from
    Isis)...


    Regards,
    Kevin
  • John Huss at Dec 10, 2011 at 10:27 pm
    So what do your pojos (entity classes) look like? Like andrus said,
    typically these have a specific implementation for cayenne. If you just
    have plain fields with fetters and setters then you will need some custom
    logic to make cayenne work with them.

    For creating the model you need to do new DataMap and then add new DbEntity
    instances and ObjEntity instances and DbAttribute and ObjAttribute
    instances need to be added to each and relationships etc. the Db* types
    need to be connected to the Obj* types.
    On Saturday, December 10, 2011, Kevin Meyer - KMZ wrote:
    On 8 Dec 2011 at 16:18, Andrus Adamchik wrote:


    In the custom module define DataDomain loading services to
    reverse-engineer the POJOs instead of loading mapping from XML. This
    is the biggest task, requiring some understanding of Cayenne APIs.
    Feel free to ask here if you get stuck with anything. Also map
    SchemaUpdateStrategy to CreateIfNoSchemaStrategy that will create a
    DB schema based on your mapping.
    Ok!

    I've decided to first try re-implementing a new Isis ObjectStore (which
    has a bespoke Isis Persistence API) before writing a whole new Isis
    Context which is independent of the Persistence API.

    Anyway.

    I now have my empty project, Isis has been told about a new
    ObjectStore (CayenneObjectStore), and in the
    CayenneObjectStore#open() method, I have created a runtime and a
    context. I also have a custom Module to inject my helpers.

    Of course, when I try create an object:
    Object o = context.newObject(persistentClass);
    I get an exception of:
    Class is not mapped with Cayenne: isis.persistor.SimpleClassA
    which is to be expected.

    So!

    I expect I need to provide a custom binder for EntityResolver?

    I'm trying:
    binder.bind(EntityResolver.class).toInstance(
    new IsisEntityResolver());

    in my custom module, but its not being picked up in the DataContext.

    But I can inject it manually:
    DataContext dc = (DataContext) context;
    dc.setEntityResolver(new IsisEntityResolver());

    Nevermind.

    What are the basics of defining DataDomain loading services to
    reverse-engineer the POJOs ?

    I already have the list of domain entities and their properties (from
    Isis)...


    Regards,
    Kevin
  • Kevin Meyer - KMZ at Dec 11, 2011 at 4:39 pm
    Thanks - I've got to the point where Cayenne is trying to instantiate an
    instance of one of my pojos, but I've run into a problem...

    Cayenne *requires* the pojo to implement the Persisted interface, but
    this interface kills the Isis introspector (it detects the XMLSerializer,
    which contains a Collections parameter, which is not supported).

    I'm looking into how to wrap the Isis user Pojo (which does not *have*
    to implement any interface or extend any class), into something that
    Cayenne can instantiate.

    Any ideas?

    Regards,
    Kevin


    So what do your pojos (entity classes) look like? Like andrus said,
    typically these have a specific implementation for cayenne. If you just
    have plain fields with fetters and setters then you will need some custom
    logic to make cayenne work with them.

    For creating the model you need to do new DataMap and then add new DbEntity
    instances and ObjEntity instances and DbAttribute and ObjAttribute
    instances need to be added to each and relationships etc. the Db* types
    need to be connected to the Obj* types.
  • Mike Kienenberger at Dec 12, 2011 at 2:18 am
    I don't really know what you're doing, but what about something like this:

    class POJO {
    CayenneDataObject delegate;

    public POJO() {
    }

    public setDelegate(CayenneDataObject cdo) {
    this.delegate = cdo;
    }

    // or

    public POJO(CayenneDataObject cdo) {
    this.delegate = cdo;
    }

    // for each attribute (and similar for each relationship)

    public type getX() {
    return delegate.readProperty("x");
    }

    public void setX(type x) {
    writeProperty("x", x);
    }
    }


    On Sun, Dec 11, 2011 at 11:38 AM, Kevin Meyer - KMZ wrote:
    Thanks - I've got to the point where Cayenne is trying to instantiate an
    instance of one of my pojos, but I've run into a problem...

    Cayenne *requires* the pojo to implement the Persisted interface, but
    this interface kills the Isis introspector (it detects the XMLSerializer,
    which contains a Collections parameter, which is not supported).

    I'm looking into how to wrap the Isis user Pojo (which does not *have*
    to implement any interface or extend any class), into something that
    Cayenne can instantiate.

    Any ideas?

    Regards,
    Kevin


    So what do your pojos (entity classes) look like?  Like andrus said,
    typically these have a specific implementation for cayenne.  If you just
    have plain fields with fetters and setters then you will need some custom
    logic to make cayenne work with them.

    For creating the model you need to do new DataMap and then add new DbEntity
    instances and ObjEntity instances and DbAttribute and ObjAttribute
    instances need to be added to each and relationships etc. the Db* types
    need to be connected to the Obj* types.
  • Kevin Meyer - KMZ at Dec 12, 2011 at 5:01 am
    By the way, I'm using Cayenne 3.1M4-SNAPSHOT.
    I don't really know what you're doing, but what about something like this:

    class POJO {
    CayenneDataObject delegate;

    public POJO() {
    }

    public setDelegate(CayenneDataObject cdo) {
    this.delegate = cdo;
    }
    I wish it were this simple. But the problem lies in
    DataContext#newObject(String entityName)
    once it has created an instance of my POJO, it type casts it to
    Persistent:
    object = (Persistent) descriptor.createObject();

    This *forces* my POJO to implement Persistent.

    Is there another way to create an instance of my POJO ?


    Why doesn't Cayenne support composition over inheritance? I think
    the idea of containing the CayenneDataObject as suggested provides
    much greater flexibility... and you generate these classes, anyway.
  • Andrus Adamchik at Dec 12, 2011 at 6:29 am

    On Dec 11, 2011, at 7:00 PM, Kevin Meyer - KMZ wrote:

    I wish it were this simple. But the problem lies in
    DataContext#newObject(String entityName)
    once it has created an instance of my POJO, it type casts it to
    Persistent:
    object = (Persistent) descriptor.createObject();

    This *forces* my POJO to implement Persistent.
    You may have to do the wrapping on your own after that I guess... If it is at all possible.

    IIRC elsewhere in this thread you said you were OK with Isis objects extending CayenneDataObject. CayenneDataObject implements Persistent of course. So maybe there was some misunderstanding earlier in this discussion? If your object really has to be a POJO (as in Java class with no special superclass and data contained in the user-defined fields), we need to backtrack quite a bit and reevaluate the problem.
    Why doesn't Cayenne support composition over inheritance? I think
    the idea of containing the CayenneDataObject as suggested provides
    much greater flexibility... and you generate these classes, anyway.
    In the Isis integration case - maybe. I don't think we've ever considered using a delegate to give persistent objects a semblance of a POJO by removing a requirement for a superclass, but still forcing our own internal structure. So it is probably worth a discussion, although I am cautiously pessimistic about it being done easily at Cayenne level.

    Andrus
  • Kevin Meyer - KMZ at Dec 12, 2011 at 6:50 am

    On 11 Dec 2011 at 20:28, Andrus Adamchik wrote:

    On Dec 11, 2011, at 7:00 PM, Kevin Meyer - KMZ wrote:

    I wish it were this simple. But the problem lies in
    DataContext#newObject(String entityName)
    once it has created an instance of my POJO, it type casts it to
    Persistent:
    object = (Persistent) descriptor.createObject();

    This *forces* my POJO to implement Persistent.
    You may have to do the wrapping on your own after that I guess... If it is at all possible.

    IIRC elsewhere in this thread you said you were OK with Isis objects
    extending CayenneDataObject. CayenneDataObject implements Persistent
    of course. So maybe there was some misunderstanding earlier in this
    discussion? If your object really has to be a POJO (as in Java class
    with no special superclass and data contained in the user-defined
    fields), we need to backtrack quite a bit and reevaluate the
    problem.
    I'm learning as I go along.

    Initially, I did not realise there would be a problem with the Isis
    introspector and CayenneDataObject.

    Fortunately, Isis provides a mechanism to bypass introspecting certain
    classes, so I am making my POJO extend CayenneDataObject and
    am on to the next stage.

    So - to recap: I have my POJO that Isis can introspect. I have
    examined the fields and created:
    DbEntity, ObjEntity for each POJO.
    For each property, I have created:
    DbAttribute, ObjAttribute
    and set the appropriate setEntity() to the entities created above.



    I can create an instance of my POJO with newInstance().

    I'm now getting a null pointer assignment when I try and commit!

    So far, I have tracked into:
    createPermIds(descriptor, objects);
    in DataDomainInsertBucket#appendQueriesInternal
    Why doesn't Cayenne support composition over inheritance? I think
    the idea of containing the CayenneDataObject as suggested provides
    much greater flexibility... and you generate these classes, anyway.
    In the Isis integration case - maybe. I don't think we've ever
    considered using a delegate to give persistent objects a semblance
    of a POJO by removing a requirement for a superclass, but still
    forcing our own internal structure. So it is probably worth a
    discussion, although I am cautiously pessimistic about it being done
    easily at Cayenne level.
    Indeed - I started putting together something in the DataContext that'll
    fetch the container via a getPersistent or equivalent, and realised that
    some additional wrappers will be needed to access the POJO again.

    I'll put that on the back-burner for a while.

    Regards,
    Kevin
  • Andrus Adamchik at Dec 12, 2011 at 7:06 am
    Great to hear there a workaround. Object structure is a pretty fundamental issue, so I was afraid we may get stuck here.

    Cheers,
    Andrus
    On Dec 11, 2011, at 8:49 PM, Kevin Meyer - KMZ wrote:
    On 11 Dec 2011 at 20:28, Andrus Adamchik wrote:

    On Dec 11, 2011, at 7:00 PM, Kevin Meyer - KMZ wrote:

    I wish it were this simple. But the problem lies in
    DataContext#newObject(String entityName)
    once it has created an instance of my POJO, it type casts it to
    Persistent:
    object = (Persistent) descriptor.createObject();

    This *forces* my POJO to implement Persistent.
    You may have to do the wrapping on your own after that I guess... If it is at all possible.

    IIRC elsewhere in this thread you said you were OK with Isis objects
    extending CayenneDataObject. CayenneDataObject implements Persistent
    of course. So maybe there was some misunderstanding earlier in this
    discussion? If your object really has to be a POJO (as in Java class
    with no special superclass and data contained in the user-defined
    fields), we need to backtrack quite a bit and reevaluate the
    problem.
    I'm learning as I go along.

    Initially, I did not realise there would be a problem with the Isis
    introspector and CayenneDataObject.

    Fortunately, Isis provides a mechanism to bypass introspecting certain
    classes, so I am making my POJO extend CayenneDataObject and
    am on to the next stage.

    So - to recap: I have my POJO that Isis can introspect. I have
    examined the fields and created:
    DbEntity, ObjEntity for each POJO.
    For each property, I have created:
    DbAttribute, ObjAttribute
    and set the appropriate setEntity() to the entities created above.



    I can create an instance of my POJO with newInstance().

    I'm now getting a null pointer assignment when I try and commit!

    So far, I have tracked into:
    createPermIds(descriptor, objects);
    in DataDomainInsertBucket#appendQueriesInternal
    Why doesn't Cayenne support composition over inheritance? I think
    the idea of containing the CayenneDataObject as suggested provides
    much greater flexibility... and you generate these classes, anyway.
    In the Isis integration case - maybe. I don't think we've ever
    considered using a delegate to give persistent objects a semblance
    of a POJO by removing a requirement for a superclass, but still
    forcing our own internal structure. So it is probably worth a
    discussion, although I am cautiously pessimistic about it being done
    easily at Cayenne level.
    Indeed - I started putting together something in the DataContext that'll
    fetch the container via a getPersistent or equivalent, and realised that
    some additional wrappers will be needed to access the POJO again.

    I'll put that on the back-burner for a while.

    Regards,
    Kevin
  • Kevin Meyer - KMZ at Dec 12, 2011 at 7:19 am
    What am I missing: In
    DataDomainInsertBucket#createPermIds
    the returned node is null in:

    DataNode node = parent.getDomain().lookupDataNode(entity.getDataMap());

    Clearly I'm not doing something in my set-up.

    On 11 Dec 2011 at 21:05, Andrus Adamchik wrote:

    Great to hear there a workaround. Object structure is a pretty
    fundamental issue, so I was afraid we may get stuck here.

    Cheers,
    Andrus
  • Kevin Meyer - KMZ at Dec 12, 2011 at 7:51 am
    Hmm.. curiouser and curiouser:
    I'm reorganising the entity setup, and now I get:

    org.apache.cayenne.CayenneRuntimeException: [v.3.1M4-SNAPSHOT Dec 11 2011 10:30:28] ObjAttribute 'number' does not have a corresponding DbAttribute

    My setup, below, links the two:
    id, in this case, is the magic "number" - the name of my POJO value
    field, of type int.

    // represents a database table
    DbEntity dbEntity = new DbEntity(entityName);

    // Represents a domain object
    ObjEntity objEntity = new ObjEntity(entityName);

    dataMap.addDbEntity(dbEntity);
    dataMap.addObjEntity(objEntity);
    // Link the table to the domain object
    objEntity.setDbEntity(dbEntity);
    objEntity.setClassName(className);

    // Create fields
    List<OneToOneAssociation> assocs = specification.getProperties();
    for (OneToOneAssociation assoc : assocs) {
    final String id = assoc.getId(); // number
    final String type = assoc.getSpecification().getFullIdentifier(); // int

    DbAttribute dbAttribute = new DbAttribute(id, java.sql.Types.INTEGER, dbEntity);
    dbEntity.addAttribute(dbAttribute);

    ObjAttribute objAttribute = new ObjAttribute(id, type, objEntity);
    objEntity.addAttribute(objAttribute);
    }

    dataMap.addObjEntity(objEntity);
    dataMap.addDbEntity(dbEntity);

    On 11 Dec 2011 at 21:05, Andrus Adamchik wrote:

    Great to hear there a workaround. Object structure is a pretty fundamental issue, so I was afraid we may get stuck here.

    Cheers,
    Andrus
  • Mike Kienenberger at Dec 12, 2011 at 3:04 pm
    I can't remember the exact details, but you might need (prefix + "." +
    id) instead of (id)
    On Mon, Dec 12, 2011 at 2:50 AM, Kevin Meyer - KMZ wrote:
    DbAttribute dbAttribute = new DbAttribute(id, java.sql.Types.INTEGER, dbEntity);
    dbEntity.addAttribute(dbAttribute);
    + // dot-separated path that starts in the root DbEntity
    that maps to this attribute's ObjEntity and spans zero or more
    relationships, always ending in a DbAttribute name.
    + objAttribute.setDbAttributePath(id);
    ObjAttribute objAttribute = new ObjAttribute(id, type, objEntity);
  • John Huss at Dec 12, 2011 at 3:21 pm
    Yes, you need to link the Obj* things to the Db* things by name, both the
    entities and the attributes.
    On Mon, Dec 12, 2011 at 9:03 AM, Mike Kienenberger wrote:

    I can't remember the exact details, but you might need (prefix + "." +
    id) instead of (id)
    On Mon, Dec 12, 2011 at 2:50 AM, Kevin Meyer - KMZ wrote:
    DbAttribute dbAttribute = new DbAttribute(id,
    java.sql.Types.INTEGER, dbEntity);
    dbEntity.addAttribute(dbAttribute);
    + // dot-separated path that starts in the root DbEntity
    that maps to this attribute's ObjEntity and spans zero or more
    relationships, always ending in a DbAttribute name.
    + objAttribute.setDbAttributePath(id);
    ObjAttribute objAttribute = new ObjAttribute(id, type,
    objEntity);
  • Kevin Meyer - KMZ at Dec 12, 2011 at 4:11 pm
    Sorry, you guys are confusing me.

    I have a datamap (called "isis_map"), to which I have added a DbEntity
    (named after my class, "simpleclass") and a ObjEntity (with same
    name).

    The "id" I refer to is the name of a property of my class (called
    "number"). The class has methods setNumber and getNumber.

    That's the id ("number") that I assigned to DbAttribute and
    ObjAttribute.

    What is the prefix you refer to?

    regards,
    Kevin
    On 12 Dec 2011 at 9:20, John Huss wrote:

    Yes, you need to link the Obj* things to the Db* things by name, both the
    entities and the attributes.
    On Mon, Dec 12, 2011 at 9:03 AM, Mike Kienenberger wrote:

    I can't remember the exact details, but you might need (prefix + "." +
    id) instead of (id)

    On Mon, Dec 12, 2011 at 2:50 AM, Kevin Meyer - KMZ <kevin@kmz.co.za>
    wrote:
    DbAttribute dbAttribute = new DbAttribute(id,
    java.sql.Types.INTEGER, dbEntity);
    dbEntity.addAttribute(dbAttribute);
    + // dot-separated path that starts in the root DbEntity
    that maps to this attribute's ObjEntity and spans zero or more
    relationships, always ending in a DbAttribute name.
    + objAttribute.setDbAttributePath(id);
    ObjAttribute objAttribute = new ObjAttribute(id, type,
    objEntity);

    --
    Kevin Meyer, PhD, Pr.Sci.Nat
    KMZ P.O. Box 9822, Sharon Park, South Africa.
    Tel: +27 11 363 2001 Cell: +27 83 346 3045
  • Mike Kienenberger at Dec 12, 2011 at 4:14 pm
    You may not need the prefix, but you at least need this much:

    // dot-separated path that starts in the root DbEntity
    that maps to this attribute's ObjEntity and spans zero or more
    relationships, always ending in a DbAttribute name.
    objAttribute.setDbAttributePath(id);
    On Mon, Dec 12, 2011 at 11:10 AM, Kevin Meyer - KMZ wrote:
    Sorry, you guys are confusing me.

    I have a datamap (called "isis_map"), to which I have added a DbEntity
    (named after my class, "simpleclass") and a ObjEntity (with same
    name).

    The "id" I refer to is the name of a property of my class (called
    "number"). The class has methods setNumber and getNumber.

    That's the id ("number") that I assigned to DbAttribute and
    ObjAttribute.

    What is the prefix you refer to?

    regards,
    Kevin
    On 12 Dec 2011 at 9:20, John Huss wrote:

    Yes, you need to link the Obj* things to the Db* things by name, both the
    entities and the attributes.
    On Mon, Dec 12, 2011 at 9:03 AM, Mike Kienenberger wrote:

    I can't remember the exact details, but you might need (prefix + "." +
    id) instead of (id)

    On Mon, Dec 12, 2011 at 2:50 AM, Kevin Meyer - KMZ <kevin@kmz.co.za>
    wrote:
    DbAttribute dbAttribute = new DbAttribute(id,
    java.sql.Types.INTEGER, dbEntity);
    dbEntity.addAttribute(dbAttribute);
    +             //  dot-separated path that starts in the root DbEntity
    that maps to this attribute's ObjEntity and spans zero or more
    relationships, always ending in a DbAttribute name.
    +             objAttribute.setDbAttributePath(id);
    ObjAttribute objAttribute = new ObjAttribute(id, type,
    objEntity);

    --
    Kevin Meyer, PhD, Pr.Sci.Nat
    KMZ             P.O. Box 9822, Sharon Park, South Africa.
    Tel: +27 11 363 2001   Cell: +27 83 346 3045
  • Kevin Meyer - KMZ at Dec 12, 2011 at 4:52 pm
    Ok, thanks, I call
    objAttribute.setDbAttributePath(id);
    and I am now back to my previous problem, where
    DataNode node =
    parent.getDomain().lookupDataNode(entity.getDataMap());
    has node == null in DataDomainInsertBucket#createPermIds.

    Any hints?
    On 12 Dec 2011 at 11:13, Mike Kienenberger wrote:

    You may not need the prefix, but you at least need this much:

    // dot-separated path that starts in the root DbEntity
    that maps to this attribute's ObjEntity and spans zero or more
    relationships, always ending in a DbAttribute name.
    objAttribute.setDbAttributePath(id);
    On Mon, Dec 12, 2011 at 11:10 AM, Kevin Meyer - KMZ wrote:
    Sorry, you guys are confusing me.

    I have a datamap (called "isis_map"), to which I have added a DbEntity
    (named after my class, "simpleclass") and a ObjEntity (with same
    name).

    The "id" I refer to is the name of a property of my class (called
    "number"). The class has methods setNumber and getNumber.

    That's the id ("number") that I assigned to DbAttribute and
    ObjAttribute.

    What is the prefix you refer to?

    regards,
    Kevin
    On 12 Dec 2011 at 9:20, John Huss wrote:

    Yes, you need to link the Obj* things to the Db* things by name, both the
    entities and the attributes.
    On Mon, Dec 12, 2011 at 9:03 AM, Mike Kienenberger wrote:

    I can't remember the exact details, but you might need (prefix + "." +
    id) instead of (id)

    On Mon, Dec 12, 2011 at 2:50 AM, Kevin Meyer - KMZ <kevin@kmz.co.za>
    wrote:
    DbAttribute dbAttribute = new DbAttribute(id,
    java.sql.Types.INTEGER, dbEntity);
    dbEntity.addAttribute(dbAttribute);
    +             //  dot-separated path that starts in the root DbEntity
    that maps to this attribute's ObjEntity and spans zero or more
    relationships, always ending in a DbAttribute name.
    +             objAttribute.setDbAttributePath(id);
    ObjAttribute objAttribute = new ObjAttribute(id, type,
    objEntity);

    --
    Kevin Meyer, PhD, Pr.Sci.Nat
    KMZ             P.O. Box 9822, Sharon Park, South Africa.
    Tel: +27 11 363 2001   Cell: +27 83 346 3045

    --
    Kevin Meyer, PhD, Pr.Sci.Nat
    KMZ P.O. Box 9822, Sharon Park, South Africa.
    Tel: +27 11 363 2001 Cell: +27 83 346 3045
  • Mike Kienenberger at Dec 12, 2011 at 5:03 pm
    How are you creating a DataNode and what are you doing to assign DataMaps to it?
    On Mon, Dec 12, 2011 at 11:52 AM, Kevin Meyer - KMZ wrote:
    Ok, thanks, I call
    objAttribute.setDbAttributePath(id);
    and I am now back to my previous problem, where
    DataNode node =
    parent.getDomain().lookupDataNode(entity.getDataMap());
    has node == null in DataDomainInsertBucket#createPermIds.

    Any hints?
    On 12 Dec 2011 at 11:13, Mike Kienenberger wrote:

    You may not need the prefix, but you at least need this much:

    //  dot-separated path that starts in the root DbEntity
    that maps to this attribute's ObjEntity and spans zero or more
    relationships, always ending in a DbAttribute name.
    objAttribute.setDbAttributePath(id);
    On Mon, Dec 12, 2011 at 11:10 AM, Kevin Meyer - KMZ wrote:
    Sorry, you guys are confusing me.

    I have a datamap (called "isis_map"), to which I have added a DbEntity
    (named after my class, "simpleclass") and a ObjEntity (with same
    name).

    The "id" I refer to is the name of a property of my class (called
    "number"). The class has methods setNumber and getNumber.

    That's the id ("number") that I assigned to DbAttribute and
    ObjAttribute.

    What is the prefix you refer to?

    regards,
    Kevin
    On 12 Dec 2011 at 9:20, John Huss wrote:

    Yes, you need to link the Obj* things to the Db* things by name, both the
    entities and the attributes.
    On Mon, Dec 12, 2011 at 9:03 AM, Mike Kienenberger wrote:

    I can't remember the exact details, but you might need (prefix + "." +
    id) instead of (id)

    On Mon, Dec 12, 2011 at 2:50 AM, Kevin Meyer - KMZ <kevin@kmz.co.za>
    wrote:
    DbAttribute dbAttribute = new DbAttribute(id,
    java.sql.Types.INTEGER, dbEntity);
    dbEntity.addAttribute(dbAttribute);
    +             //  dot-separated path that starts in the root DbEntity
    that maps to this attribute's ObjEntity and spans zero or more
    relationships, always ending in a DbAttribute name.
    +             objAttribute.setDbAttributePath(id);
    ObjAttribute objAttribute = new ObjAttribute(id, type,
    objEntity);

    --
    Kevin Meyer, PhD, Pr.Sci.Nat
    KMZ             P.O. Box 9822, Sharon Park, South Africa.
    Tel: +27 11 363 2001   Cell: +27 83 346 3045

    --
    Kevin Meyer, PhD, Pr.Sci.Nat
    KMZ             P.O. Box 9822, Sharon Park, South Africa.
    Tel: +27 11 363 2001   Cell: +27 83 346 3045
  • Kevin Meyer - KMZ at Dec 12, 2011 at 6:10 pm
    I don't believe that I am creating a DataNode...where does this fit in?

    My initialisation currently looks like:
    IsisPropertiesModule pm = new IsisPropertiesModule();
    runtime = new ServerRuntime("cayenne-project.xml", pm);
    context = runtime.getContext();

    dataContext = (DataContext) context;

    final EntityResolver entityResolver = dataContext.getEntityResolver();
    dataMap = entityResolver.getDataMap("isis_map");
    if (dataMap == null) {
    dataMap = new DataMap("isis_map");
    entityResolver.addDataMap(dataMap);
    }

    where IsisPropertiesModule was an attempt to add a property fetcher
    from the properties file:

    public void configure(Binder binder) {
    MapBuilder<Object> mapBuilder = binder.bindMap(DefaultRuntimeProperties.PROPERTIES_MAP);
    Properties props = new Properties();

    props.put("cayenne.jdbc.driver", "org.hsqldb.jdbcDriver");
    props.put("cayenne.jdbc.connection", "jdbc:hsqldb:file:hsql-db/tests");
    props.put("cayenne.jdbc.user", "sa");
    props.put("cayenne.jdbc.password", "");

    for (Object keyObj : props.keySet()) {
    String key = (String) keyObj;
    mapBuilder.put(key, props.get(key));
    }
    }

    but it doesn't have any effect.

    My "empty" cayenne-project.xml contains:
    <?xml version="1.0" encoding="utf-8"?>
    <domain project-version="6">
    <map name="datamap"/>
    <node name="datanode"
    factory="org.apache.cayenne.configuration.server.XMLPoolingDataSourceFactory"
    schema-update-strategy="org.apache.cayenne.access.dbsync.CreateIfNoSchemaStrategy"
    >
    <!-- <map-ref name="datamap"/> -->
    <data-source>
    <driver value="org.hsqldb.jdbcDriver"/>
    <url value="jdbc:hsqldb:file:hsql-db/tests"/>
    <connectionPool min="1" max="10"/>
    <login userName="sa"/>
    </data-source>
    </node>
    </domain>

    I would like to not have to have this xml file, and reproduce everything
    programmatically.

    Regards,
    Kevin

    On 12 Dec 2011 at 12:02, Mike Kienenberger wrote:

    How are you creating a DataNode and what are you doing to assign DataMaps to it?
    On Mon, Dec 12, 2011 at 11:52 AM, Kevin Meyer - KMZ wrote:
    Ok, thanks, I call
    objAttribute.setDbAttributePath(id);
    and I am now back to my previous problem, where
    DataNode node =
    parent.getDomain().lookupDataNode(entity.getDataMap());
    has node == null in DataDomainInsertBucket#createPermIds.

    Any hints?
  • Kevin Meyer - KMZ at Dec 12, 2011 at 6:21 pm
    Ah! Next problem.

    Having found the datanode with:
    DataDomain dataDomain = runtime.getInjector().getInstance(DataDomain.class);
    DataNode dataNode = dataDomain.getNode("datanode");
    ...
    dataNode.addDataMap(dataMap);


    I now get the following in the log:
    20:15:15,961 [CommonsJdbcEventLogger main INFO ] +++ Connecting: SUCCESS.
    20:15:16,071 [CommonsJdbcEventLogger main INFO ] Detected and installed adapter: org.apache.cayenne.dba.hsqldb.HSQLDBAdapter
    20:15:16,075 [CommonsJdbcEventLogger main INFO ] --- transaction started.
    20:15:16,123 [CreateIfNoSchemaStrategy main INFO ] No schema detected, will create mapped tables
    20:15:16,130 [CommonsJdbcEventLogger main INFO ] CREATE CACHED TABLE SimpleClassA (number INTEGER NULL, persistent INTEGER NULL)
    20:15:16,253 [CommonsJdbcEventLogger main INFO ] CREATE TABLE AUTO_PK_SUPPORT ( TABLE_NAME CHAR(100) NOT NULL, NEXT_ID BIGINT NOT NULL, PRIMARY KEY(TABLE_NAME))
    20:15:16,254 [CommonsJdbcEventLogger main INFO ] DELETE FROM AUTO_PK_SUPPORT WHERE TABLE_NAME IN ()
    20:15:16,258 [CommonsJdbcEventLogger main INFO ] *** error.
    java.sql.SQLException: Unexpected token: ) in statement [DELETE FROM AUTO_PK_SUPPORT WHERE TABLE_NAME IN ()]
    at org.hsqldb.jdbc.Util.sqlException(Unknown Source)
    at org.hsqldb.jdbc.jdbcStatement.fetchResult(Unknown Source)
    at org.hsqldb.jdbc.jdbcStatement.execute(Unknown Source)
    at org.apache.cayenne.access.DbGenerator.safeExecute(DbGenerator.java:377)
    at org.apache.cayenne.access.DbGenerator.runGenerator(DbGenerator.java:355)
    at org.apache.cayenne.access.dbsync.CreateIfNoSchemaStrategy.generate(CreateIfNoSchemaStrategy.java:79)
    ....
    ....
    20:15:16,287 [CommonsJdbcEventLogger main INFO ] INSERT INTO SimpleClassA (number, persistent) VALUES (?, ?)
    20:15:16,290 [CommonsJdbcEventLogger main INFO ] [bind: 1->number:NULL, 2->persistent:NULL]
    20:15:16,292 [CommonsJdbcEventLogger main INFO ] === updated 1 row.
    20:17:32,778 [CommonsJdbcEventLogger main INFO ] --- transaction started.
    20:17:32,779 [CommonsJdbcEventLogger main INFO ] INSERT INTO SimpleClassA (number, persistent) VALUES (?, ?)
    20:17:32,779 [CommonsJdbcEventLogger main INFO ] [bind: 1->number:NULL, 2->persistent:NULL]
    20:17:32,780 [CommonsJdbcEventLogger main INFO ] === updated 1 row.
    20:17:32,780 [CommonsJdbcEventLogger main INFO ] [bind: 1->number:NULL, 2->persistent:NULL]
    20:17:32,780 [CommonsJdbcEventLogger main INFO ] === updated 1 row.


    Followed by "Temporary ID hasn't been replaced on commit: "

    Any hints?


    On 12 Dec 2011 at 12:02, Mike Kienenberger wrote:

    How are you creating a DataNode and what are you doing to assign DataMaps to it?
    On Mon, Dec 12, 2011 at 11:52 AM, Kevin Meyer - KMZ wrote:
    Ok, thanks, I call
    objAttribute.setDbAttributePath(id);
    and I am now back to my previous problem, where
    DataNode node =
    parent.getDomain().lookupDataNode(entity.getDataMap());
    has node == null in DataDomainInsertBucket#createPermIds.

    Any hints?
    On 12 Dec 2011 at 11:13, Mike Kienenberger wrote:

    You may not need the prefix, but you at least need this much:

    //  dot-separated path that starts in the root DbEntity
    that maps to this attribute's ObjEntity and spans zero or more
    relationships, always ending in a DbAttribute name.
    objAttribute.setDbAttributePath(id);
    On Mon, Dec 12, 2011 at 11:10 AM, Kevin Meyer - KMZ wrote:
    Sorry, you guys are confusing me.

    I have a datamap (called "isis_map"), to which I have added a DbEntity
    (named after my class, "simpleclass") and a ObjEntity (with same
    name).

    The "id" I refer to is the name of a property of my class (called
    "number"). The class has methods setNumber and getNumber.

    That's the id ("number") that I assigned to DbAttribute and
    ObjAttribute.

    What is the prefix you refer to?

    regards,
    Kevin
    On 12 Dec 2011 at 9:20, John Huss wrote:

    Yes, you need to link the Obj* things to the Db* things by name, both the
    entities and the attributes.
    On Mon, Dec 12, 2011 at 9:03 AM, Mike Kienenberger wrote:

    I can't remember the exact details, but you might need (prefix + "." +
    id) instead of (id)

    On Mon, Dec 12, 2011 at 2:50 AM, Kevin Meyer - KMZ <kevin@kmz.co.za>
    wrote:
    DbAttribute dbAttribute = new DbAttribute(id,
    java.sql.Types.INTEGER, dbEntity);
    dbEntity.addAttribute(dbAttribute);
    +             //  dot-separated path that starts in the root DbEntity
    that maps to this attribute's ObjEntity and spans zero or more
    relationships, always ending in a DbAttribute name.
    +             objAttribute.setDbAttributePath(id);
    ObjAttribute objAttribute = new ObjAttribute(id, type,
    objEntity);

    --
    Kevin Meyer, PhD, Pr.Sci.Nat
    KMZ             P.O. Box 9822, Sharon Park, South Africa.
    Tel: +27 11 363 2001   Cell: +27 83 346 3045

    --
    Kevin Meyer, PhD, Pr.Sci.Nat
    KMZ             P.O. Box 9822, Sharon Park, South Africa.
    Tel: +27 11 363 2001   Cell: +27 83 346 3045

    --
    Kevin Meyer, PhD, Pr.Sci.Nat
    KMZ P.O. Box 9822, Sharon Park, South Africa.
    Tel: +27 11 363 2001 Cell: +27 83 346 3045
  • Kevin Meyer - KMZ at Dec 12, 2011 at 6:38 pm
    Hah! Success!

    It seemed that I did not have a primary key field defined. I define that,
    and I have just had a successful commit.

    *) newObject
    *) assign
    *) commit

    works.

    Does Cayenne provide a SQL Data type helper? Something that helps
    Cayenne guess SQL data types for given value types? Or must I
    implement my own?

    Regards,
    Kevin

    On 12 Dec 2011 at 20:21, Kevin Meyer - KMZ wrote:

    Ah! Next problem.

    Having found the datanode with:
    DataDomain dataDomain = runtime.getInjector().getInstance(DataDomain.class);
    DataNode dataNode = dataDomain.getNode("datanode");
    ...
    dataNode.addDataMap(dataMap);


    I now get the following in the log:
    20:15:15,961 [CommonsJdbcEventLogger main INFO ] +++ Connecting: SUCCESS.
    20:15:16,071 [CommonsJdbcEventLogger main INFO ] Detected and installed adapter: org.apache.cayenne.dba.hsqldb.HSQLDBAdapter
    20:15:16,075 [CommonsJdbcEventLogger main INFO ] --- transaction started.
    20:15:16,123 [CreateIfNoSchemaStrategy main INFO ] No schema detected, will create mapped tables
    20:15:16,130 [CommonsJdbcEventLogger main INFO ] CREATE CACHED TABLE SimpleClassA (number INTEGER NULL, persistent INTEGER NULL)
    20:15:16,253 [CommonsJdbcEventLogger main INFO ] CREATE TABLE AUTO_PK_SUPPORT ( TABLE_NAME CHAR(100) NOT NULL, NEXT_ID BIGINT NOT NULL, PRIMARY KEY(TABLE_NAME))
    20:15:16,254 [CommonsJdbcEventLogger main INFO ] DELETE FROM AUTO_PK_SUPPORT WHERE TABLE_NAME IN ()
    20:15:16,258 [CommonsJdbcEventLogger main INFO ] *** error.
    java.sql.SQLException: Unexpected token: ) in statement [DELETE FROM AUTO_PK_SUPPORT WHERE TABLE_NAME IN ()]
    at org.hsqldb.jdbc.Util.sqlException(Unknown Source)
    at org.hsqldb.jdbc.jdbcStatement.fetchResult(Unknown Source)
    at org.hsqldb.jdbc.jdbcStatement.execute(Unknown Source)
    at org.apache.cayenne.access.DbGenerator.safeExecute(DbGenerator.java:377)
    at org.apache.cayenne.access.DbGenerator.runGenerator(DbGenerator.java:355)
    at org.apache.cayenne.access.dbsync.CreateIfNoSchemaStrategy.generate(CreateIfNoSchemaStrategy.java:79)
    ....
    ....
    20:15:16,287 [CommonsJdbcEventLogger main INFO ] INSERT INTO SimpleClassA (number, persistent) VALUES (?, ?)
    20:15:16,290 [CommonsJdbcEventLogger main INFO ] [bind: 1->number:NULL, 2->persistent:NULL]
    20:15:16,292 [CommonsJdbcEventLogger main INFO ] === updated 1 row.
    20:17:32,778 [CommonsJdbcEventLogger main INFO ] --- transaction started.
    20:17:32,779 [CommonsJdbcEventLogger main INFO ] INSERT INTO SimpleClassA (number, persistent) VALUES (?, ?)
    20:17:32,779 [CommonsJdbcEventLogger main INFO ] [bind: 1->number:NULL, 2->persistent:NULL]
    20:17:32,780 [CommonsJdbcEventLogger main INFO ] === updated 1 row.
    20:17:32,780 [CommonsJdbcEventLogger main INFO ] [bind: 1->number:NULL, 2->persistent:NULL]
    20:17:32,780 [CommonsJdbcEventLogger main INFO ] === updated 1 row.


    Followed by "Temporary ID hasn't been replaced on commit: "

    Any hints?


    On 12 Dec 2011 at 12:02, Mike Kienenberger wrote:

    How are you creating a DataNode and what are you doing to assign DataMaps to it?
    On Mon, Dec 12, 2011 at 11:52 AM, Kevin Meyer - KMZ wrote:
    Ok, thanks, I call
    objAttribute.setDbAttributePath(id);
    and I am now back to my previous problem, where
    DataNode node =
    parent.getDomain().lookupDataNode(entity.getDataMap());
    has node == null in DataDomainInsertBucket#createPermIds.

    Any hints?
    On 12 Dec 2011 at 11:13, Mike Kienenberger wrote:

    You may not need the prefix, but you at least need this much:

    //  dot-separated path that starts in the root DbEntity
    that maps to this attribute's ObjEntity and spans zero or more
    relationships, always ending in a DbAttribute name.
    objAttribute.setDbAttributePath(id);
    On Mon, Dec 12, 2011 at 11:10 AM, Kevin Meyer - KMZ wrote:
    Sorry, you guys are confusing me.

    I have a datamap (called "isis_map"), to which I have added a DbEntity
    (named after my class, "simpleclass") and a ObjEntity (with same
    name).

    The "id" I refer to is the name of a property of my class (called
    "number"). The class has methods setNumber and getNumber.

    That's the id ("number") that I assigned to DbAttribute and
    ObjAttribute.

    What is the prefix you refer to?

    regards,
    Kevin
    On 12 Dec 2011 at 9:20, John Huss wrote:

    Yes, you need to link the Obj* things to the Db* things by name, both the
    entities and the attributes.
    On Mon, Dec 12, 2011 at 9:03 AM, Mike Kienenberger wrote:

    I can't remember the exact details, but you might need (prefix + "." +
    id) instead of (id)

    On Mon, Dec 12, 2011 at 2:50 AM, Kevin Meyer - KMZ <kevin@kmz.co.za>
    wrote:
    DbAttribute dbAttribute = new DbAttribute(id,
    java.sql.Types.INTEGER, dbEntity);
    dbEntity.addAttribute(dbAttribute);
    +             //  dot-separated path that starts in the root DbEntity
    that maps to this attribute's ObjEntity and spans zero or more
    relationships, always ending in a DbAttribute name.
    +             objAttribute.setDbAttributePath(id);
    ObjAttribute objAttribute = new ObjAttribute(id, type,
    objEntity);

    --
    Kevin Meyer, PhD, Pr.Sci.Nat
    KMZ             P.O. Box 9822, Sharon Park, South Africa.
    Tel: +27 11 363 2001   Cell: +27 83 346 3045

    --
    Kevin Meyer, PhD, Pr.Sci.Nat
    KMZ             P.O. Box 9822, Sharon Park, South Africa.
    Tel: +27 11 363 2001   Cell: +27 83 346 3045

    --
    Kevin Meyer, PhD, Pr.Sci.Nat
    KMZ P.O. Box 9822, Sharon Park, South Africa.
    Tel: +27 11 363 2001 Cell: +27 83 346 3045

    --
    Kevin Meyer, PhD, Pr.Sci.Nat
    KMZ P.O. Box 9822, Sharon Park, South Africa.
    Tel: +27 11 363 2001 Cell: +27 83 346 3045
  • Kevin Meyer - KMZ at Dec 12, 2011 at 7:02 pm
    Enough for tonight.

    Thanks to everyone for the help thus far.

    When I get back to this project, I'll be looking into starting/ending
    transactions and getting IDs before the object is persisted.

    Regards,
    Kevin
    Hah! Success!

    It seemed that I did not have a primary key field defined. I define that,
    and I have just had a successful commit.

    *) newObject
    *) assign
    *) commit

    works.

    Does Cayenne provide a SQL Data type helper? Something that helps
    Cayenne guess SQL data types for given value types? Or must I
    implement my own?
  • Andrus Adamchik at Dec 12, 2011 at 11:11 pm

    On Dec 12, 2011, at 8:37 AM, Kevin Meyer - KMZ wrote:

    Hah! Success!

    It seemed that I did not have a primary key field defined. I define that,
    and I have just had a successful commit.

    *) newObject
    *) assign
    *) commit

    works.
    Congrats! :)
    Does Cayenne provide a SQL Data type helper? Something that helps
    Cayenne guess SQL data types for given value types? Or must I
    implement my own?
    This class has some static methods that should help you:

    http://cayenne.apache.org/doc/api/org/apache/cayenne/dba/TypesMapping.html

    Andrus
  • Mike Kienenberger at Dec 12, 2011 at 2:58 pm
    Yes, I'm sorry if I wasn't clear. The wrapping of CayenneDataObject
    would be handled in your own code.

    It's definitely possible -- I used this kind of a strategy for a while
    with a project that could support either JPA or Cayenne as a back-end.
    Generated code was the key for me to keep it manageable -- instead of
    generating only CayenneDataObjects, I also generated the JPA classes
    as well as the wrapping classes.
    On Mon, Dec 12, 2011 at 1:28 AM, Andrus Adamchik wrote:
    On Dec 11, 2011, at 7:00 PM, Kevin Meyer - KMZ wrote:

    I wish it were this simple. But the problem lies in
    DataContext#newObject(String entityName)
    once it has created an instance of my POJO, it type casts it to
    Persistent:
    object = (Persistent) descriptor.createObject();

    This *forces* my POJO to implement Persistent.
    You may have to do the wrapping on your own after that I guess... If it is at all possible.

    IIRC elsewhere in this thread you said you were OK with Isis objects extending CayenneDataObject. CayenneDataObject implements Persistent of course. So maybe there was some misunderstanding earlier in this discussion? If your object really has to be a POJO (as in Java class with no special superclass and data contained in the user-defined fields), we need to backtrack quite a bit and reevaluate the problem.
    Why doesn't Cayenne support composition over inheritance? I think
    the idea of containing the CayenneDataObject as suggested provides
    much greater flexibility... and you generate these classes, anyway.
    In the Isis integration case - maybe. I don't think we've ever considered using a delegate to give persistent objects a semblance of a POJO by removing a requirement for a superclass, but still forcing our own internal structure. So it is probably worth a discussion, although I am cautiously pessimistic about it being done easily at Cayenne level.

    Andrus

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
groupuser @
categoriescayenne
postedDec 6, '11 at 7:00a
activeDec 12, '11 at 11:11p
posts30
users4
websitecayenne.apache.org

People

Translate

site design / logo © 2022 Grokbase