I have an application that consumes incoming messages, parses the data present in the message, and then applies rules to that data. On the Rule entity, there's a column that distinguishes the type of rule.
I want to persist the Result of the rule to separate tables or subclasses, depending on what type of Rule processed them.
I'm currently solving this by creating a parent @MappedSuperclass
(abstract) BaseResult object and an AppleResult and OrangeResult @Enitiy
that extends the BaseResult.
My question is, given the statement below, how can I improve/annotate my objects in the model so that I don't have to do an instanceof check for each instance as I go to access/persist it? Right now this is what I'm having to do to avoid "baseresult does not exist" SQL grammar exceptions:
public void save(BaseResult baseResult) {
if (baseResult instanceof AppleResult) {
jpaApi.em().merge((AppleResult) baseResult);
} else if (baseResult instanceof OrangeResult) {
jpaApi.em().merge((OrangeResult) baseResult);
}
}
I'm hoping there's a more elegant solution than having to do a if/else and explicitly cast depending on the result. I've looking into using things like @DiscriminatorValue
annotation of using Generics, but these all seem to require that the BaseResult
in my case is also an entity, which it's not.
You should use @Inheritance
. Then, saving would be as simple as:
public void save(final BaseResult baseResult) {
jpaApi.em().merge(baseResult);
}
Which inheritance strategy to use depends on your current database design, but I'm guessing that you have a table for each of the subclasses, so something like this:
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class BaseResult {
//...
}
@Entity
public class AppleResult extends BaseResult {
//...
}
Having @Entity
on the superclass is not a problem, as it is abstract
anyways..
Also, using merge
is usually something one shouldn't do, you should just manipulate your entities within a transaction and it's automatically persisted in the database upon commit of the transaction:
@Transactional //either this...
public void doStuff(final ResultCommand command) {
//begin transaction <-- ...or this
final BaseResult result = em.find(BaseResult.class, command.getResultId());
result.apply(command);
//end transaction
}