Issue Details (XML | Word | Printable)

Key: ANN-140
Type: Bug Bug
Status: Resolved Resolved
Resolution: Rejected
Priority: Major Major
Assignee: Unassigned
Reporter: Steven Grimm
Votes: 0
Watchers: 9
Operations

If you were logged in you would be able to see more operations.
z - Hibernate Annotations

Discriminator column not supported with JOINED strategy

Created: 05/Nov/05 02:48 PM   Updated: 29/Jul/09 06:51 AM   Resolved: 05/Nov/05 04:46 PM
Return to search
Component/s: None
Affects Version/s: 3.1beta6
Fix Version/s: None

Time Tracking:
Not Specified

Environment: Hibernate 3.1rc2, Hibernate Annotations 3.1b6
Issue Links:
Cloners
 

Bug Testcase Reminder (view):
REMINDER: Bug reports should generally be accompanied by a test case
Participants: Amit Kasher, Constantine Voronin, Emmanuel Bernard, Erwin Bolwidt, Gavin King, Gérald Quintana, Ortwin Glück, Pavel , Sergey Generalov and Steven Grimm


 Description  « Hide

Section 9.1.27 of the EJB3 persistence public draft says, "The DiscriminatorColumn annotation is used to define the discriminator column for SINGLE_TABLE and JOINED mapping strategies." But Hibernate ignores the DiscriminatorColumn annotation when the mapping strategy is JOINED; when a JOINED entity is persisted, its discriminator column is not included in the SQL "insert" statement, resulting in a not-null constraint violation if the discriminator column is marked NOT NULL in the database.

The JOINED strategy with discriminators is pretty ubiquitous in EJB3 sample code and tutorials out on the net, so lots of people are likely to run into this as they try out EJB3 for the first time. A few examples:

http://www.oracle.com/technology/tech/java/oc4j/ejb3/howtos-ejb3/howtoejb30inheritance/doc/how-to-ejb30-inheritance.html
http://www.solarmetric.com/Software/Documentation/4.0.0EA/docs/full/html/ejb3_overview_mapping_discrim.html
http://www.caucho.com/resin-3.0/amber/tutorial/cmp-inherit/index.xtp



Gavin King added a comment - 05/Nov/05 04:46 PM

EJB3 does NOT require use of discriminators with JOINED mapping strategies. It is allowed for inferior implementations of the JOINED mapping strategy which require a discriminator. Hibernate does not need a discriminator because Hibernate is better than these other inferior implementations.


Steven Grimm added a comment - 05/Nov/05 07:30 PM

Hibernate may be better in other respects, but those other so-called "inferior" implementations can handle the following object model much more cleanly than Hibernate can:

@Entity(access=FIELD)
@Inheritance(strategy=JOINED)
public class TopLevel {
@Id
public int id;
... some other properties ...
}

@Entity(access=FIELD)
@Inheritance(discriminatorValue="middle")
public class ConcreteMiddleLevel extends TopLevel {
public int prop1;
public String prop2;
}

@Entity(access=FIELD)
public abstract class AbstractMiddleLevel extends TopLevel {
public String prop3;
public int prop4;
}

@Entity
@Inheritance(discriminatorValue="bottom1")
public class BottomLevel1 extends AbstractMiddleLevel { }

@Entity
@Inheritance(discriminatorValue="bottom2")
public class BottomLevel2 extends AbstractMiddleLevel { }

Without using discriminator values, how can Hibernate possibly distinguish between instances of BottomLevel1 and BottomLevel2, since they have no properties (and thus no tables of their own to outer-join with)?

The only way to model this with Hibernate, as far as I can tell, is to use the SINGLE_TABLE strategy and put @SecondaryTable on all the subclasses that have properties – at which point you also have to annotate each and every property with @Column(secondaryTable="whatever"). Which kind of defeats the purpose of EJB3's "configure by exception" philosophy.


Ortwin Glück added a comment - 23/Aug/06 09:43 AM

A discriminator column can also be used to choose the right subclass for a lazy proxy. Now in a lazy OneToOne the proxy is always the topmost class, which is bad, because there is no way of telling the real class behind the proxy! I strongly suggest to revisit this issue and use an optional discriminator column as a hint.

See http://forum.hibernate.org/viewtopic.php?p=2319629#2319629 for an example.


Emmanuel Bernard added a comment - 23/Aug/06 05:49 PM

discriminator is not gonna help your case.


Erwin Bolwidt added a comment - 03/Dec/06 07:59 AM

I don't understand Gavin's stance on this issue.
Yes, Hibernate is very smart and its way of doing joined subclasses has superios performance over implementations that require a discriminator column.
But hibernate's algorithm doesn't prevent a discriminator column. In fact, Hibernate itself supports discriminator columns with joined subclasses, so why are you explicitly disallowing it in hibernate annotations?

It leaves users out in the cold who are using a legacy database; the only way to get around it is to not use annotations for the superclass and all subclasses.

In addition to that, even if a discriminator column never gives any performance bonuses, it still makes the database model more resilient. If for some reason (dbas mucking about the database by hand, other apps interfering with the direct use of sql) data ends up in multiple subclass tables, a discriminator column makes it possible to clean up the database, since it is the judge on what the intended subclass was.

Please change the three lines of code and make it possible to configure discriminator columns with joined subclasses using hibernate annotations.


Emmanuel Bernard added a comment - 03/Dec/06 09:26 AM

Patch welcome, but it's probably more 3k lines than 3


Amit Kasher added a comment - 21/Feb/07 06:06 AM

I'd like to add another possible requirement for discriminator column support. If you have a discriminator column, you can have it inside DB constraints, and achieve constraints in which subclasses participate as different entities.

Example: I have the following entities:

A {
id, name
}

B extends A {
height
}

C extends A {
width
}

I need the following constraint: I don't want to allow (more than 1 2 or more instances of B with the same name, and I don't want (more than 1 2 or more instances of C with the same name. However, I DO want to allow 1 instance of B with the name "Jack", and another instance, this time of C, with that same name, "Jack". The only way to achieve this, I think, is having a discriminator column in A which will allow you to define a unique constraint containing A.discriminator and A.name.


Pavel added a comment - 18/Feb/08 04:06 PM

It would be nice to see how the problem with the multiple joins is faced when the underlying DB has restriction on the number of joins one can execute in a single SQL? For instance MySQL seems to allow only 31 joins. What happens if the class hierarchy has more than 31 sub-classes?


Constantine Voronin added a comment - 05/Nov/08 05:00 AM

I've the same problem with strategy=JOINED and Discriminator Values.
It's very important to me to have not null value of discriminator field, I use it in group queries.

Now I have to do in base classes something like:

public MyBase () { // set the value of discriminator's field kind = this.getClass().getSimpleName(); }

I think it is really ugly


Sergey Generalov added a comment - 29/Apr/09 05:23 AM

4 years passed since this issue was opened.
Any changes?

"Status: Resolved Resolved
Resolution: Rejected "

Rejected? Why? This is very important functionality. Can anyone tell why this issue was skipped, please.


Gérald Quintana added a comment - 29/Jul/09 06:51 AM

Using discriminator column with "joined" strategy used to work when we were using .hbm.xml files to describe ORM. Moreover it's clearly documentated:
http://docs.jboss.org/hibernate/stable/core/reference/fr/html/inheritance.html#inheritance-tablepersubclass-discriminator

SInce we moved to annotations instead of XML files, we can't do that anymore except using secondary tables but it's painful.