Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it bad practice to use DiscriminatorFormula for migration of Hibernate databases?

I have an application using Hibernate for data persistence, with Spring on top (for good measure). Until recently, there was one persistent class in the application, A:

@Entity
public class A {
  @Id
  @Column(unique = true, nullable = false, updatable = false)
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private long id;
  public String name;
}

I have since added a subclass of A, called B:

@Entity
public class B extends A {
  public String description;
}

After adding B, I could now not load A's. The following exception was thrown:

class org.springframework.orm.hibernate3.HibernateObjectRetrievalFailureException :: Object with id: 1 was not of the specified subclass: A (Discriminator: null); nested exception is org.hibernate.WrongClassException: Object with id: 1 was not of the specified subclass: A (Discriminator: null)

I added the following annotation and property to B, and it seems to have solved the problem. Is this the right way to solve the issue?

...
@DiscriminatorFormula("(CASE WHEN dtype IS NULL THEN 'A' ELSE dtype END)")
public class A {
    private String dtype = this.getClass().getSimpleName();
    ...
like image 465
Armand Avatar asked Nov 05 '22 10:11

Armand


1 Answers

(...) Until recently, there was one persistent class in the application, A:

With the following database representation:

ID  NAME
--  ----
 1   foo
 2   bar

I have since added a subclass of A, called B (...)

And you didn't specify the Inheritance annotation so the SINGLE_TABLE mapping strategy is used. And In this strategy, all the classes in a hierarchy are mapped to a single table. The table has a column that serves as a “discriminator column”, that is, a column whose value identifies the specific subclass to which the instance that is represented by the row belongs.

The table then became:

ID  NAME DTYPE
--  ---- -----
 1   foo  NULL
 2   bar  NULL

Where DTYPE is the default name of column to be used for the discriminator.

After adding B, I could now not load A's. The following exception was thrown (...)

Indeed, because existing values have a null value in the discriminator column, the provider doesn't know what subclass to instantiate.

I added the following annotation and property to B, and it seems to have solved the problem. Is this the right way to solve the issue?

That's one way but it is intrusive (your entities shouldn't be aware of the dtype column) and Hibernate specific. In other words, it's a hack.

For me, the "right" way to solve this would be to update the DTYPE column of existing A records to set the value to 'A' (with Hibernate, the value defaults to the entity name):

UPDATE A SET DTYPE='A' WHERE DTYPE=NULL

This way, Hibernate would be able to load them properly.

like image 171
Pascal Thivent Avatar answered Nov 11 '22 03:11

Pascal Thivent