views:

389

answers:

2

Put another way: How do you model/map a heavily reused child class/table to many different parent entities?

I have several entity types each being persisted into its own table:

class A --> table A class B --> table B ....

Now I need to make each of these classes the parent of a 1:M unidirectional child collection. The collection is a history of approvals the entity has gained over time. The Child domain class is called "ApprovalItem". The Approval class is exactly the same for all types of parents.

What is the best way to map this? If I create a single table to hold all ApprovalItems, then I can't enforce a FK relation to the PK of the entity and/or I am left with a bad database design.

On the other hand, I could create an ApprovalIems table for each entity type (e.g. A_ApprovalItems, B_ApprovalItems, etc.). This seems like a good schema on the database side, but then it seems I need to create a separate domain classes in Java for each entity approval (e.g. AAprrovalItem class, BApprovalItem class, etc.). This seems like a lot of hassle and complexity to create so many new classes in Java that do nothing other than allow me to put in different JPA mapping annotations.

Is there a mapping technique in Hibernate that will allow me to have one class in Java map to several different tables depending on who the parent owner of the collection is?

+2  A: 

Chapter 8. Inheritance Mapping of Hibernate Documentation might help.

Otherwise, I see no problem having multiple ApprovalItem derived class that "do nothing", like you say, since it does differentiate the Approval, it's like having a type of approval. Seeing your model like so, I would recommend using multiple classes, even if they only inherit from your base ApprovalItem class.

Have I well understood your question or am I missing something else more subtle?

Will Marcouiller
I think you understood the problem perfectly. I was just trying to avoid the multiplicity of classes as I have 12 of these entities and 3 different child collections. That's 36 domain classes that do nothing other than hold different JPA annotations. Just hate the idea of persistence polluting my domain representation! But your suggestion is what I'll do if nothing better comes along....thanks.
HDave
I get your point and understand your argumentation. Despite, it is not polluting your domain model, it's only precising it. Perhaps was it your model that was not sufficient for your current needs. Anyway, glad I helped. =)
Will Marcouiller
+2  A: 

Hi,

I could create an ApprovalItem table for each entity type (e.g. A_ApprovalItem, B_ApprovalItem, etc.). This seems like a good schema on the database side

But

It seems i need to create a separate domain classes in Java for each entity approval (e.g. AAprrovalItem class, BApprovalItem class, etc.).

You do not need it. you can create a single ApprovalItem class and create a @OneToMany relationship between your parent classes and your ApprovalItem. Hibernate takes care to create a linked table for each relationship.

@Entity
public class ClassA {

    @Id
    @GeneratedValue 
    private Integer id;

    // Hibernate will create CLASSA_APPROVALITEM to link both class
    @OneToMany
    private List<ApprovalItem> approvalItemList;

}

@Entity
public class ClassB {

    @Id
    @GeneratedValue 
    private Integer id;

    // Hibernate will create CLASSB_APPROVALITEM to link both class
    @OneToMany
    private List<ApprovalItem> approvalItemList;

}

And your ApprovalItem class

@Entity
public class ApprovalItem {

    @Id
    @GeneratedValue 
    private Integer id;

    // Nothing else

}

But Let's see what Java Persistence with Hibernate book talks about it

You may have shared references to the Bid objects. As suggested earlier, a User may have a collection of references to the Bid instances they made. You can’t delete an item and all its bids without removing these references first. You may get an exception if you try to commit this transaction, because a foreign key constraint may be violated.

So keep it in mind when dealing with shared references.

In order to see how the target schema looks like, you can use the following

AnnotationConfiguration configuration = new AnnotationConfiguration();

configuration
    .addAnnotatedClass(ClassA.class)
    .addAnnotatedClass(ClassB.class)
    .addAnnotatedClass(ApprovalItem.class)
    .setProperty(Environment.USER, <TYPE_YOUR_USER>)
    .setProperty(Environment.PASS, <TYPE_YOUR_PASSWORD>)
    .setProperty(Environment.URL, <TYPE_YOUR_URL>)
    .setProperty(Environment.DIALECT, <TYPE_YOUR_DIALECT>)
    .setProperty(Environment.DRIVER, <TYPE_YOUR_DRIVER>);

SchemaExport schema = new SchemaExport(configuration);
schema.setOutputFile("schema.sql");

schema.create(<DO_YOU_WANT_TO_PRINT_TO_THE_CONSOLE>, <DO_YOU_WANT_TO_EXPORT_THE_SCRIPT_TO_THE_DATABASE>);

It will generate a file called schema.sql, which contains your target schema

regards,

Arthur Ronald F D Garcia
Looks perfect on the Java side, but can you elaborate on what the schema looks like in the database? I take it there is a join table between the entity tables and the approvalitem table - is this right?
HDave
@HDave Yes, We have three classes: ClassA, ClassB and ApprovalItem; and Five tables: CLASSA, CLASSB, APPROVALITEM, CLASSA_APPROVALITEM (It takes care to link ClassA and ApprovalItem instances) CLASSB_APPROVALITEM (It takes care to link ClassB and ApprovalItem instances)
Arthur Ronald F D Garcia
100% awesome goodness....thanks.
HDave