You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@cayenne.apache.org by Jeremias Maerki <de...@jeremias-maerki.ch> on 2009/05/12 10:40:54 UTC

Interfaces for domain objects?

Hi there,

after years of not having to deal with databases, I'm back to that topic.
So I'm still figuring out the best way for myself to do ORM. My first
two attempts were to use JCR (Jackrabbit) and JPA (OpenJPA). JCR worked
fine although I dropped it because I can easily have >100'000 children
on one node which will result in performance problems or require
work-arounds that I don't particularly like. JPA then just went against
my views of how databases should be modeled: an intermediate table for a
simple 1:n relation. Not with me. I couldn't get the whole thing to work
without the intermediate table. Then I stumbled upon Cayenne (I'm using
the Trunk) and immediately found myself at home.

Now, my problem: I've been trying to make an abstraction of my data
logic using interfaces, i.e. define an interface for each domain object
and logic methods grouped in an interface per topic. That works pretty
well for the JCR and JPA implementations. I wrote the test code once and
can reuse it for all implementations. With Cayenne, this gets a bit
difficult. I can always implement the domain interfaces in the domain
classes but when it comes to nested collections, this becomes a problem:

public interface Document extends Serializable {

[..]

    Collection<Representation> getRepresentations();

}

public interface Representation extends Serializable {
[..]
}

Generated domain class:

public class DocumentImpl extends _DocumentImpl implements Document {
[..]
}

public abstract class _DocumentImpl extends CayenneDataObject {
[..]
    @SuppressWarnings("unchecked")
    public List<RepresentationImpl> getRepresentations() {
        return (List<RepresentationImpl>)readProperty("representations");
    }
}

List<RepresentationImpl> is not compatible with the List<Representation>
in the interface.

So, I'm wondering if there's a better way to do this that avoids this
problem, preferably without removing generics.

I was thinking that adding the interface in the object model could
optionally be specified and the code generator could, for example, do an
"implements Document" for _DocumentImpl and return List<Representation>.
Of course, that would require some casting to DataObject in
addToManyTarget() for example. That's probably undesired and would probably
require quite a bit of work. But maybe there's a better way. I could
probably proxy/adapt the whole stuff but that's probably bad
performance- and effort-wise. Maybe I simply have to give up my puristic
data access abstraction. But I wanted to ask around first.

---

While I'm at it: Can I ask why DeleteQuery has been deprecated? I'd
rather use that instead of EJBQLQuery. Not having to concatenate strings
to build queries is one of the features that makes Cayenne appeal to me
so much. I've had stuff like that back in my Delphi times and I liked
that very much.


Thanks a lot for any ideas and thoughts,
Jeremias Maerki


Re: Interfaces for domain objects?

Posted by Jeremias Maerki <de...@jeremias-maerki.ch>.
On 13.05.2009 19:19:14 Andrus Adamchik wrote:
> 
> On May 12, 2009, at 4:40 AM, Jeremias Maerki wrote:
> 
> > While I'm at it: Can I ask why DeleteQuery has been deprecated? I'd
> > rather use that instead of EJBQLQuery. Not having to concatenate  
> > strings
> > to build queries is one of the features that makes Cayenne appeal to  
> > me
> > so much. I've had stuff like that back in my Delphi times and I liked
> > that very much.
> 
> 
> The problem with DeleteQuery (or EJBQL delete for that matter) is that  
> it didn't clean up in-memory objects that were deleted in the DB. So  
> the feeling was that it is conceptually wrong as a public user API.  
> The preferred way is get a hold of an object and do  
> context.deleteObject(..).

Thanks for the explanation. I don't see a problem with having special
queries around that don't update the local context. I mean, something
not under Cayenne's control could always access the database directly
and modify things that Cayenne doesn't notice. As long as the user of
the DeleteQuery is aware of its behaviour it is a powerful tool for
certain situations.

> Of course the need for a batch delete operation doesn't completely go  
> away with the above. I guess we may need to work on getting it right  
> as a part of the planned post 3.0 effort to merge redundant queries  
> together and provide them all with a non-String OO creation interface.

That'd be great.


Thanks,
Jeremias Maerki


Re: Interfaces for domain objects?

Posted by Andrus Adamchik <an...@objectstyle.org>.
On May 12, 2009, at 4:40 AM, Jeremias Maerki wrote:

> While I'm at it: Can I ask why DeleteQuery has been deprecated? I'd
> rather use that instead of EJBQLQuery. Not having to concatenate  
> strings
> to build queries is one of the features that makes Cayenne appeal to  
> me
> so much. I've had stuff like that back in my Delphi times and I liked
> that very much.


The problem with DeleteQuery (or EJBQL delete for that matter) is that  
it didn't clean up in-memory objects that were deleted in the DB. So  
the feeling was that it is conceptually wrong as a public user API.  
The preferred way is get a hold of an object and do  
context.deleteObject(..).

Of course the need for a batch delete operation doesn't completely go  
away with the above. I guess we may need to work on getting it right  
as a part of the planned post 3.0 effort to merge redundant queries  
together and provide them all with a non-String OO creation interface.

Andrus

Re: Interfaces for domain objects?

Posted by Jeremias Maerki <de...@jeremias-maerki.ch>.
Looks like I still have a few things to learn about generics. Thanks a
lot! Works fine.

On 13.05.2009 19:27:07 Andrus Adamchik wrote:
> 
> On May 12, 2009, at 4:40 AM, Jeremias Maerki wrote:
> 
> >   Collection<Representation> getRepresentations();
> 
> Ain't Java generics fun. Here is the version of the same design that  
> will be allowed to compile:
> 
>    Interface:      Collection<? extends Representation>  
> getRepresentations();
>    Implementation: Collection<RepresentationImpl> getRepresentations()  
> {..}
> 
> Andrus



Thanks,
Jeremias Maerki (who's been doing Java 1.3 & 1.4 for that past 4 years)


Re: Interfaces for domain objects?

Posted by Andrus Adamchik <an...@objectstyle.org>.
On May 12, 2009, at 4:40 AM, Jeremias Maerki wrote:

>   Collection<Representation> getRepresentations();

Ain't Java generics fun. Here is the version of the same design that  
will be allowed to compile:

   Interface:      Collection<? extends Representation>  
getRepresentations();
   Implementation: Collection<RepresentationImpl> getRepresentations()  
{..}

Andrus

Re: Interfaces for domain objects?

Posted by Robert Zeigler <ro...@roxanemy.com>.
It's certainly true that it's possible with JPA, but, at least when  
using Hibernate as the JPA provider, if you don't explicitly fiddle  
with the mappings, you get an intermediate table by default; at least,  
I've always had to add extra mapping information to achieve an  
intermediate-tableless schema.

Robert

On May 13, 2009, at 5/1312:31 PM , Mike Kienenberger wrote:

> It's certainly possible to develop templates that provide entity
> interfaces.  I've done so in past projects.
>
> And if you mess around with the generic signatures enough, you can
> probably solve those problems as well.
>
> While I won't recommend JPA (since I am now having to use it instead
> of Cayenne), it's also not a problem to define 1:n relationships
> without intermediate join tables.   We have many one-to-many and
> many-to-one relationships defined in JPA, and none of them have
> intermediate join tables.  In fact, you can have a one-to-many
> relationship defined in a single object, so it's not a JPA issue.   I
> still recommend using Cayenne instead of JPA, though.
>
> object:
>   - column: ID
>   - column: PARENT_ID
>   - relationship: parentObject
>   - relationship: childObjectList
>
>
>
> On Tue, May 12, 2009 at 4:40 AM, Jeremias Maerki <dev@jeremias-maerki.ch 
> > wrote:
>> Hi there,
>>
>> after years of not having to deal with databases, I'm back to that  
>> topic.
>> So I'm still figuring out the best way for myself to do ORM. My first
>> two attempts were to use JCR (Jackrabbit) and JPA (OpenJPA). JCR  
>> worked
>> fine although I dropped it because I can easily have >100'000  
>> children
>> on one node which will result in performance problems or require
>> work-arounds that I don't particularly like. JPA then just went  
>> against
>> my views of how databases should be modeled: an intermediate table  
>> for a
>> simple 1:n relation. Not with me. I couldn't get the whole thing to  
>> work
>> without the intermediate table. Then I stumbled upon Cayenne (I'm  
>> using
>> the Trunk) and immediately found myself at home.
>>
>> Now, my problem: I've been trying to make an abstraction of my data
>> logic using interfaces, i.e. define an interface for each domain  
>> object
>> and logic methods grouped in an interface per topic. That works  
>> pretty
>> well for the JCR and JPA implementations. I wrote the test code  
>> once and
>> can reuse it for all implementations. With Cayenne, this gets a bit
>> difficult. I can always implement the domain interfaces in the domain
>> classes but when it comes to nested collections, this becomes a  
>> problem:
>>
>> public interface Document extends Serializable {
>>
>> [..]
>>
>>    Collection<Representation> getRepresentations();
>>
>> }
>>
>> public interface Representation extends Serializable {
>> [..]
>> }
>>
>> Generated domain class:
>>
>> public class DocumentImpl extends _DocumentImpl implements Document {
>> [..]
>> }
>>
>> public abstract class _DocumentImpl extends CayenneDataObject {
>> [..]
>>    @SuppressWarnings("unchecked")
>>    public List<RepresentationImpl> getRepresentations() {
>>        return  
>> (List<RepresentationImpl>)readProperty("representations");
>>    }
>> }
>>
>> List<RepresentationImpl> is not compatible with the  
>> List<Representation>
>> in the interface.
>>
>> So, I'm wondering if there's a better way to do this that avoids this
>> problem, preferably without removing generics.
>>
>> I was thinking that adding the interface in the object model could
>> optionally be specified and the code generator could, for example,  
>> do an
>> "implements Document" for _DocumentImpl and return  
>> List<Representation>.
>> Of course, that would require some casting to DataObject in
>> addToManyTarget() for example. That's probably undesired and would  
>> probably
>> require quite a bit of work. But maybe there's a better way. I could
>> probably proxy/adapt the whole stuff but that's probably bad
>> performance- and effort-wise. Maybe I simply have to give up my  
>> puristic
>> data access abstraction. But I wanted to ask around first.
>>
>> ---
>>
>> While I'm at it: Can I ask why DeleteQuery has been deprecated? I'd
>> rather use that instead of EJBQLQuery. Not having to concatenate  
>> strings
>> to build queries is one of the features that makes Cayenne appeal  
>> to me
>> so much. I've had stuff like that back in my Delphi times and I liked
>> that very much.
>>
>>
>> Thanks a lot for any ideas and thoughts,
>> Jeremias Maerki
>>
>>


Re: Interfaces for domain objects?

Posted by Jeremias Maerki <de...@jeremias-maerki.ch>.
Thanks to all of you for your feedback!

On 13.05.2009 19:31:32 Mike Kienenberger wrote:
> It's certainly possible to develop templates that provide entity
> interfaces.  I've done so in past projects.
> 
> And if you mess around with the generic signatures enough, you can
> probably solve those problems as well.

Yep, Andrus had the right hints for me.

> While I won't recommend JPA (since I am now having to use it instead
> of Cayenne), it's also not a problem to define 1:n relationships
> without intermediate join tables.   We have many one-to-many and
> many-to-one relationships defined in JPA, and none of them have
> intermediate join tables.  In fact, you can have a one-to-many
> relationship defined in a single object, so it's not a JPA issue.   I
> still recommend using Cayenne instead of JPA, though.

At any rate, I've had some trouble getting that to work with OpenJPA. It
would bark at me with at least two different attempts (based on info in
the documentation and from the net). At some point, I've just given up,
having lost too much time. Now that I'm on Cayenne, things have been
running pretty smoothly, even more now that I can reenable my domain
interfaces again. Very cool.

> object:
>    - column: ID
>    - column: PARENT_ID
>    - relationship: parentObject
>    - relationship: childObjectList
> 
> 
> 
> On Tue, May 12, 2009 at 4:40 AM, Jeremias Maerki <de...@jeremias-maerki.ch> wrote:
> > Hi there,
> >
> > after years of not having to deal with databases, I'm back to that topic.
> > So I'm still figuring out the best way for myself to do ORM. My first
> > two attempts were to use JCR (Jackrabbit) and JPA (OpenJPA). JCR worked
> > fine although I dropped it because I can easily have >100'000 children
> > on one node which will result in performance problems or require
> > work-arounds that I don't particularly like. JPA then just went against
> > my views of how databases should be modeled: an intermediate table for a
> > simple 1:n relation. Not with me. I couldn't get the whole thing to work
> > without the intermediate table. Then I stumbled upon Cayenne (I'm using
> > the Trunk) and immediately found myself at home.
> >
> > Now, my problem: I've been trying to make an abstraction of my data
> > logic using interfaces, i.e. define an interface for each domain object
> > and logic methods grouped in an interface per topic. That works pretty
> > well for the JCR and JPA implementations. I wrote the test code once and
> > can reuse it for all implementations. With Cayenne, this gets a bit
> > difficult. I can always implement the domain interfaces in the domain
> > classes but when it comes to nested collections, this becomes a problem:
> >
> > public interface Document extends Serializable {
> >
> > [..]
> >
> >    Collection<Representation> getRepresentations();
> >
> > }
> >
> > public interface Representation extends Serializable {
> > [..]
> > }
> >
> > Generated domain class:
> >
> > public class DocumentImpl extends _DocumentImpl implements Document {
> > [..]
> > }
> >
> > public abstract class _DocumentImpl extends CayenneDataObject {
> > [..]
> >    @SuppressWarnings("unchecked")
> >    public List<RepresentationImpl> getRepresentations() {
> >        return (List<RepresentationImpl>)readProperty("representations");
> >    }
> > }
> >
> > List<RepresentationImpl> is not compatible with the List<Representation>
> > in the interface.
> >
> > So, I'm wondering if there's a better way to do this that avoids this
> > problem, preferably without removing generics.
> >
> > I was thinking that adding the interface in the object model could
> > optionally be specified and the code generator could, for example, do an
> > "implements Document" for _DocumentImpl and return List<Representation>.
> > Of course, that would require some casting to DataObject in
> > addToManyTarget() for example. That's probably undesired and would probably
> > require quite a bit of work. But maybe there's a better way. I could
> > probably proxy/adapt the whole stuff but that's probably bad
> > performance- and effort-wise. Maybe I simply have to give up my puristic
> > data access abstraction. But I wanted to ask around first.
> >
> > ---
> >
> > While I'm at it: Can I ask why DeleteQuery has been deprecated? I'd
> > rather use that instead of EJBQLQuery. Not having to concatenate strings
> > to build queries is one of the features that makes Cayenne appeal to me
> > so much. I've had stuff like that back in my Delphi times and I liked
> > that very much.
> >
> >
> > Thanks a lot for any ideas and thoughts,
> > Jeremias Maerki
> >
> >




Jeremias Maerki


Re: Interfaces for domain objects?

Posted by Mike Kienenberger <mk...@gmail.com>.
It's certainly possible to develop templates that provide entity
interfaces.  I've done so in past projects.

And if you mess around with the generic signatures enough, you can
probably solve those problems as well.

While I won't recommend JPA (since I am now having to use it instead
of Cayenne), it's also not a problem to define 1:n relationships
without intermediate join tables.   We have many one-to-many and
many-to-one relationships defined in JPA, and none of them have
intermediate join tables.  In fact, you can have a one-to-many
relationship defined in a single object, so it's not a JPA issue.   I
still recommend using Cayenne instead of JPA, though.

object:
   - column: ID
   - column: PARENT_ID
   - relationship: parentObject
   - relationship: childObjectList



On Tue, May 12, 2009 at 4:40 AM, Jeremias Maerki <de...@jeremias-maerki.ch> wrote:
> Hi there,
>
> after years of not having to deal with databases, I'm back to that topic.
> So I'm still figuring out the best way for myself to do ORM. My first
> two attempts were to use JCR (Jackrabbit) and JPA (OpenJPA). JCR worked
> fine although I dropped it because I can easily have >100'000 children
> on one node which will result in performance problems or require
> work-arounds that I don't particularly like. JPA then just went against
> my views of how databases should be modeled: an intermediate table for a
> simple 1:n relation. Not with me. I couldn't get the whole thing to work
> without the intermediate table. Then I stumbled upon Cayenne (I'm using
> the Trunk) and immediately found myself at home.
>
> Now, my problem: I've been trying to make an abstraction of my data
> logic using interfaces, i.e. define an interface for each domain object
> and logic methods grouped in an interface per topic. That works pretty
> well for the JCR and JPA implementations. I wrote the test code once and
> can reuse it for all implementations. With Cayenne, this gets a bit
> difficult. I can always implement the domain interfaces in the domain
> classes but when it comes to nested collections, this becomes a problem:
>
> public interface Document extends Serializable {
>
> [..]
>
>    Collection<Representation> getRepresentations();
>
> }
>
> public interface Representation extends Serializable {
> [..]
> }
>
> Generated domain class:
>
> public class DocumentImpl extends _DocumentImpl implements Document {
> [..]
> }
>
> public abstract class _DocumentImpl extends CayenneDataObject {
> [..]
>    @SuppressWarnings("unchecked")
>    public List<RepresentationImpl> getRepresentations() {
>        return (List<RepresentationImpl>)readProperty("representations");
>    }
> }
>
> List<RepresentationImpl> is not compatible with the List<Representation>
> in the interface.
>
> So, I'm wondering if there's a better way to do this that avoids this
> problem, preferably without removing generics.
>
> I was thinking that adding the interface in the object model could
> optionally be specified and the code generator could, for example, do an
> "implements Document" for _DocumentImpl and return List<Representation>.
> Of course, that would require some casting to DataObject in
> addToManyTarget() for example. That's probably undesired and would probably
> require quite a bit of work. But maybe there's a better way. I could
> probably proxy/adapt the whole stuff but that's probably bad
> performance- and effort-wise. Maybe I simply have to give up my puristic
> data access abstraction. But I wanted to ask around first.
>
> ---
>
> While I'm at it: Can I ask why DeleteQuery has been deprecated? I'd
> rather use that instead of EJBQLQuery. Not having to concatenate strings
> to build queries is one of the features that makes Cayenne appeal to me
> so much. I've had stuff like that back in my Delphi times and I liked
> that very much.
>
>
> Thanks a lot for any ideas and thoughts,
> Jeremias Maerki
>
>