0

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.

daniel9x
  • 755
  • 2
  • 11
  • 28

1 Answers1

1

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
}
Tobb
  • 11,850
  • 6
  • 52
  • 77
  • Awesome! Thanks so much. Worked like a charm. Curious about the snippet below that regarding using oldStateEntity.apply(newState). I am not seeing the .apply method available when I try that...? – daniel9x Apr 23 '17 at 21:38
  • It's just an example of a way to manipulate the state of the entity. Since I don't know what you are actually doing to the entity I went for something generic. – Tobb Apr 24 '17 at 17:40