How to annotation abstract class or interface

3 messages Options
Embed this post
Permalink
Kevin Cox

How to annotation abstract class or interface

Reply Threaded More More options
Print post
Permalink
Hi all,
I have a question about inheritance strategies pertaining to abstract classes and interfaces. An abstract class and an interface are very similar when there are only abstract method declarations; no shared implementation, no common properties...  The question pertains to both cases where and abstract class has common parts or not.  The question also pertains when you have multiple polymorphic classes implementing an interface.

Setting the stage - JPA defines three inheritance strategies:
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@Inheritance(strategy=InheritanceType.JOINED)
@Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)

The interface is covered using @ManagedInterface

However, none of these strategies really do what I think I want to happen.  So, I need to take the closest one an annotate further.

My desired is to
1) Have a table per class to reduce joins and multiple statements for CRUD operations (performance opt for a truck load of data).  I have a bunch of types and don’t want a super sparse SINGLE_TABLE.
2) Be able to directly resolve an object instance when the class/type and id are known (1 select statement, nicely indexed), e.g. using em.find(X.class, id)
3) Be able to resolve a type when only the id is know (not the class) (2 selects, both indexed)  Or, maybe there’s a better way?

InheritanceType.TABLE_PER_CLASS gets me the closest, except it does not appear to provide a way to for #3 without querying every table representing the  implementation for the abstract class or interface.  You would have to query every table until you find the id.  Once the id is found, you would know the table which corresponds to the class.  The problem is that a table is not created for the abstract class or interface to allow the reverse lookup of the id to the class/type.

Does JPA contain something to deal with the situation? How would one go about creating the table for the abstract class or interface?

I think the possible solutions are:
1) Use an ID class as the @Id of your abstract class or interface (@IdClass) even though the id is not compound
2) Create a Type class as a property on the abstract class or interface
3) Use an id that is a combination of type plus sequence number where the type portion can be used to resolve the class. Like circle123456, circle is a type of shape.  The embedded “circle” make the id a string rather than a number, but alleviates the need for a table for the abstract class or interface.

Here’s the example with an abstract class:

@Entity
@Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
@DiscriminatorColumn(discriminatorType = DiscriminatorType.STRING)
public abstract class Item {

    @SequenceGenerator(name="ItemSeq", sequenceName="ITEM_SEQ")
    @Id @GeneratedValue(strategy= GenerationType.SEQUENCE, generator="ItemSeq")
    private long id;

    private String someCommonValue;
...
}

@Entity
public class ItemA extends Item {
 ... Defines additional properties for type A
}
@Entity
public class ItemB extends Item {
 ... Defines additional properties for type B
}


The same example with interfaces and no common value is:

@Entity
@ManagedInterface
public interface Item {

    @SequenceGenerator(name="ItemSeq", sequenceName="ITEM_SEQ")
    @Id @GeneratedValue(strategy= GenerationType.SEQUENCE, generator="ItemSeq")
    long getId();
    void setId(lond id);
}

@Entity
public class ItemA implements Item {
    private long id; //each class holds it’s own id based on the sequence in the interface definition
 ... Defines additional properties for type A and implement getId, setId
}
@Entity
public class ItemB implements Item {
    private long id; //each class holds it’s own id based on the sequence in the interface definition
 ... Defines additional properties for type B and implement getId, setId
}

So, how do you think about this problem?  What would you do?  Would your JPA versus non-JPA approaches be different?  Any recommended approaches please?
Thanks,
Kevin
Kevin Sutter

Re: How to annotation abstract class or interface

Reply Threaded More More options
Print post
Permalink
Kevin,
I haven't taken the time to completely absorb your proposal (it is a Friday
night after all...), but I will offer one bit of advice...  The
TABLE_PER_CLASS inheritance type is not widely used nor recommended.  And,
I've heard rumors that it might even be deprecated in the JPA 2.0
specification.  Granted, even if it's deprecated, it will be supported for
some period of time.  Just an observation...

Kevin

On Fri, Oct 10, 2008 at 1:01 PM, Kevin Cox <[hidden email]> wrote:

>
> Hi all,
> I have a question about inheritance strategies pertaining to abstract
> classes and interfaces. An abstract class and an interface are very similar
> when there are only abstract method declarations; no shared implementation,
> no common properties...  The question pertains to both cases where and
> abstract class has common parts or not.  The question also pertains when
> you
> have multiple polymorphic classes implementing an interface.
>
> Setting the stage - JPA defines three inheritance strategies:
> @Inheritance(strategy=InheritanceType.SINGLE_TABLE)
> @Inheritance(strategy=InheritanceType.JOINED)
> @Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
>
> The interface is covered using @ManagedInterface
>
> However, none of these strategies really do what I think I want to happen.
> So, I need to take the closest one an annotate further.
>
> My desired is to
> 1) Have a table per class to reduce joins and multiple statements for CRUD
> operations (performance opt for a truck load of data).  I have a bunch of
> types and don't want a super sparse SINGLE_TABLE.
> 2) Be able to directly resolve an object instance when the class/type and
> id
> are known (1 select statement, nicely indexed), e.g. using em.find(X.class,
> id)
> 3) Be able to resolve a type when only the id is know (not the class) (2
> selects, both indexed)  Or, maybe there's a better way?
>
> InheritanceType.TABLE_PER_CLASS gets me the closest, except it does not
> appear to provide a way to for #3 without querying every table representing
> the  implementation for the abstract class or interface.  You would have to
> query every table until you find the id.  Once the id is found, you would
> know the table which corresponds to the class.  The problem is that a table
> is not created for the abstract class or interface to allow the reverse
> lookup of the id to the class/type.
>
> Does JPA contain something to deal with the situation? How would one go
> about creating the table for the abstract class or interface?
>
> I think the possible solutions are:
> 1) Use an ID class as the @Id of your abstract class or interface
> (@IdClass)
> even though the id is not compound
> 2) Create a Type class as a property on the abstract class or interface
> 3) Use an id that is a combination of type plus sequence number where the
> type portion can be used to resolve the class. Like circle123456, circle is
> a type of shape.  The embedded "circle" make the id a string rather than a
> number, but alleviates the need for a table for the abstract class or
> interface.
>
> Here's the example with an abstract class:
>
> @Entity
> @Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
> @DiscriminatorColumn(discriminatorType = DiscriminatorType.STRING)
> public abstract class Item {
>
>    @SequenceGenerator(name="ItemSeq", sequenceName="ITEM_SEQ")
>    @Id @GeneratedValue(strategy= GenerationType.SEQUENCE,
> generator="ItemSeq")
>    private long id;
>
>    private String someCommonValue;
> ...
> }
>
> @Entity
> public class ItemA extends Item {
>  ... Defines additional properties for type A
> }
> @Entity
> public class ItemB extends Item {
>  ... Defines additional properties for type B
> }
>
>
> The same example with interfaces and no common value is:
>
> @Entity
> @ManagedInterface
> public interface Item {
>
>    @SequenceGenerator(name="ItemSeq", sequenceName="ITEM_SEQ")
>    @Id @GeneratedValue(strategy= GenerationType.SEQUENCE,
> generator="ItemSeq")
>    long getId();
>    void setId(lond id);
> }
>
> @Entity
> public class ItemA implements Item {
>    private long id; //each class holds it's own id based on the sequence in
> the interface definition
>  ... Defines additional properties for type A and implement getId, setId
> }
> @Entity
> public class ItemB implements Item {
>    private long id; //each class holds it's own id based on the sequence in
> the interface definition
>  ... Defines additional properties for type B and implement getId, setId
> }
>
> So, how do you think about this problem?  What would you do?  Would your
> JPA
> versus non-JPA approaches be different?  Any recommended approaches please?
> Thanks,
> Kevin
>
> --
> View this message in context:
> http://n2.nabble.com/How-to-annotation-abstract-class-or-interface-tp1317137p1317137.html
> Sent from the OpenJPA Users mailing list archive at Nabble.com.
>
>
Kevin Cox

Re: How to annotation abstract class or interface

Reply Threaded More More options
Print post
Permalink
I saw the section on page 50 of the JPA 2.0 spec you are referring to.
Quoted below for other readers:

<quote>
Support for the table per concrete class inheritance mapping strategy is
optional in this release.

[Note to reviewers] We would welcome feedback as to the whether support for
this mapping strategy should be required.

Support for the combination of inheritance strategies
</quote>

For my current project, I have decided to go with the JOINED inheritance
type.  This decision is due to the what I think of as incompleteness of the
TABLE_PER_CLASS approach.

I my opinion, any inheritance strategy must support the basic capabilities
1) Save a deep inheritance or polymorphic model
2) Load an inheritance or polymorphic model
2a) Directly when the type is known (id and type are known)
2b) Determine the type when the type is not known (just id is known)

Everything else is a performance and/or storage optimization consideration,
and this is typically where coders and DBA/data modelers get into trouble.
One could also argue that 2a and 2b are performance related also, but they
are tied to the mechanisms of the language.  This is where the impedance
mismatch between objects and relational tables lives.  The classic old
debate happens here and guides the design.  Most people select a design that
best matches their app's needs. It isn't cookie cutter, however there are
established best practices which JPA is trying to capitalize on.

I definitely don't think that TABLE_PER_CLASS should be dropped from the
spec.  It represents a valid approach for some apps, especially when join
performance chokes your app.  I think that capability 2b above needs to be
implemented as part (or optionally) of the approach.

The trade offs are
1. Performance: Joins for unions (JOINED or TABLE_PER_CLASS)
2. Performance: Join queries vs multiple non-join queries
3. Performance: Searching for a type when the type is unknown - multiple
queries vs one query to find the type corresponding to the entity id (
TABLE_PER_CLASS is incomplete)
4. Storage: Sparse tables for normalized tables (SINGLE_TABLE vs (JOINED or
TABLE_PER_CLASS))