2

So I have an interesting situation. I've inherited a big mess of code where the original developer decided to forego using inheritance in favor of enums and switch statements...it's a perfect example of this anti-pattern Now it's time to refactor, and I've decided the best way to go about it is to pull out a superclass backed by a table with shared columns and then use the joined subclass inheritance strategy. So far so good...

Now the tricky part is that this code has already been deployed to a production system. Accordingly, my refactored code has to be backwards-compatible with the schema/data out there, and I can't start dropping redundant columns off of the subclass tables until one release in the future. Like it or not, I'm going to have duplicated columns between the parent and child tables for one release cycle.

Luckily for me, hibernate doesn't flip out when it sees that there are duplicate columns between parent and child tables. But the bad news is that it doesn't update said duplicated columns in both tables. The column in the parent table gets updated, but the one in the child is left stale.

For backward-compatibility with the current code, I'd like for the column to be updated in both tables. That way, updates to the entities aren't lost if we have to rollback the release and go back to the old schema. While I know that I could take care of this via triggers, I'm looking for a code-only solution because triggers have a nasty habit of flying under the radar.

Is there anyone out there who can tell me a way to convince hibernate to hit both columns?

A very contrived example of my classes is:

@Entity
@Table(name = "superclass")
@Inheritance(strategy = InheritanceType.JOINED)
public class SuperClass {

    @Id @Generated
    Long id;
    boolean duplicate;
}

@Entity
@Table(name = "subclass")
public class SubClass extends SuperClass {
    String otherProperty;
}

With the tables to match:

CREATE TABLE superclass (
    id INT PRIMARY KEY AUTO_INCREMENT,
    duplicate BOOLEAN
);

CREATE TABLE subclass (
    id INT NOT NULL,
    duplicate BOOLEAN,
    otherProperty VARCHAR(255),
    FOREIGN KEY (id) REFERENCES superclass(id)
);

When inserting a new SubClass entity, the duplicate column on the subclass table will be NULL.

Thanks a bunch!

stevevls
  • 10,675
  • 1
  • 45
  • 50

1 Answers1

1

How about defining two properties in your code, mapping one to each column, then keeping them in sync in the code? One is the real property, and one is a sort of shadow property. It's not pretty, but it should be confined to the implementation of one class (or one class and its superclass).

When you are able to drop the column, you can remove the shadow property.

Tom Anderson
  • 46,189
  • 17
  • 92
  • 133
  • Hmm...while I'm sure that would work, it would be a lot of code duplication. I'm hoping that there's some hibernate magic that I can invoke to update both columns. – stevevls May 18 '11 at 16:04
  • Yeah, override the original property setter in the subclass so that It updates both the original property and the "shadow" one. Properly encapsulate the shadow property in a way that it can't be mutated by its own. – Anthony Accioly May 18 '11 at 16:07
  • 1
    Well, i was hoping for something magic. This is the only code solution I've been able to come up with. Though in the end, we've decided to solve it in a simpler way...if we have to rollback, we'll just run a SQL script to back copy columns. Sometimes the organizational solution is better than the code one. ;) – stevevls May 20 '11 at 11:50
  • That sounds like a much better solution than fixing it in code. You should probably have posted it as an answer and accepted it, in fact! – Tom Anderson May 20 '11 at 15:35