views:

207

answers:

2

Hi - this is potentially a bit complex, so I'll do my best to describe my situation - it's also my first post here, so please forgive formatting mistakes, etc!

I'm using JPA with joined inheritance and a database structure that looks like:

ACTION
---------
ACTION_ID
ACTION_MAPPING_ID
ACTION_TYPE

DELIVERY_CHANNEL_ACTION
--------------------------
ACTION_ID
CHANNEL_ID

OVERRIDE_ADDRESS_ACTION
--------------------------
ACTION_ID
(various fields specific to this action type)

So, in plain English, I have multiple different types of action, all share an ACTION_MAPPING, which is referenced from the 'parent' ACTION table. DELIVERY_CHANNEL_ACTION and OVERRIDE_ADDRESS_ACTION both have extra, supplementary data of their own, and are mapped to ACTION with a FK.

Real-world, I also have a 'suppress' action, but this doesn't have any supplementary data of its own, so it doesn't have a corresponding table - all it needs is an ACTION_MAPPING, which is stored in the ACTION table.

Hopefully you're with me so far...

I'm creating a new project from scratch, so am pretty flexible in what I can do, but obviously would like to get it right from the outset!

My current implementation, which works, has three entities loosely defined as follows:

@Entity
@Table(name="ACTION")
@Inheritance(strategy=InheritanceType.JOINED)
@DiscriminatorValue("SUPPRESS")
public class Action

@Entity
@Table(name="DELIVERY_CHANNEL_ACTION")
@DiscriminatorValue("DELIVERY_CHANNEL")
public class DeliveryChannelAction extends Action

@Entity
@Table(name="OVERRIDE_ADDRESS_ACTION")
@DiscriminatorValue("OVERRIDE_ADDRESS")
public class OverrideAddressAction extends Action

That is - I have a concrete base class, Action, with a Joined inheritance strategy. DeliveryChannelAction and OverrideAddressAction both extend Action.

What feels wrong here though, is that my Action class is the base class for these two actions, but also forms the concrete implementation for the suppress action.

For the time being this works, but at some point more actions are likely to be added, and there's every chance that some of them will, like SUPPRESS, have no supplementary data, which will start to get difficult!

So... what I would like to do, in the object model world, is to have Action be abstract, and create a SuppressAction class, which is empty apart from having a @DiscriminatorValue("SUPPRESS").

I've tried doing exactly what is described above, so, changing Action to:

@Entity
@Table(name="ACTION")
@Inheritance(strategy=InheritanceType.JOINED)
public abstract class Action

and creating:

@DiscriminatorValue("SUPPRESS")
public class SuppressAction extends Action

but no luck - it seems to work fine for DeliveryChannelAction and OverrideAddressAction, but when I try to create a SuppressAction and persist it, I get:

java.lang.IllegalArgumentException: Object: com.mypackage.SuppressAction[actionId=null] is not a known entity type.
    at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.registerNewObjectForPersist(UnitOfWorkImpl.java:4147)
    at org.eclipse.persistence.internal.jpa.EntityManagerImpl.persist(EntityManagerImpl.java:368)
    at com.mypackage.test.util.EntityTestUtil.createSuppressAction(EntityTestUtil.java:672)
    at com.mypackage.entities.ActionTest.testCRUDAction(ActionTest.java:27)

which I assume is down to the fact that SuppressAction isn't registered as an entity, but I don't know how I can do that, given that it doesn't have an associated table.

Any pointers, either complete answers or hints for things to Google (I'm out of ideas!), most welcome :)

EDIT: to correct my stacktrace.

+1  A: 

You can, with InheritanceType.SINGLE_TABLE

There are ways to have multiple inheritance types for different branches. See this question.

Bozho
Thanks - this might be an option, but I really want to keep it as InheritanceType.JOINED, if at all possible; the number of actions might get quite large, and each might have many specific fields, so I'm trying to avoid a single behemoth of a table!
DaveyDaveDave
@DaveyDaveDave then you need mixed inheritance types.. check my update.
Bozho
Thanks Bozho, this looks like it might have done what I was looking for, but I found a simpler option that seems to have worked for me, so I'll stick with that, but I'll bear yours in mind if mine proves not to work later. If you don't mind reading my solution above, and letting me know if there's anything glaringly stupid, that would be great! Thanks!
DaveyDaveDave
A: 

I think I found a solution that should work for me, my entities now look like:

@Entity
@Table(name="ACTION")
@Inheritance(strategy=InheritanceType.JOINED)
@DiscriminatorValue("SUPPRESS")
public abstract class Action

@Entity
@Table(name="DELIVERY_CHANNEL_ACTION")
@DiscriminatorValue("DELIVERY_CHANNEL")
public class DeliveryChannelAction extends Action

@Entity
@Table(name="OVERRIDE_ADDRESS_ACTION")
@DiscriminatorValue("OVERRIDE_ADDRESS")
public class OverrideAddressAction extends Action

@Entity
@Table(name="ACTION")
@DiscriminatorValue("SUPPRESS")
public class SuppressAction extends Action

So, basically all I was missing was referencing the 'parent' table in my SuppressAction class, which I had foolishly assumed wouldn't work. All my tests are passing with this, and it seems to be working; it seems like it will be happy if I need to add other Actions in the future, a copy of SuppressAction, with a different @DiscriminatorValue works as expected, so I think I'm happy.

DaveyDaveDave