|
|
|
Kevin Cox
|
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
|
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 <kc6522@...> 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
|
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)) |
||||||||||||||||
| Free Embeddable Forum Powered by Nabble | Help |