Why is @DiscriminatorColumn ignored when using @JoinTable?

半城伤御伤魂 提交于 2019-12-23 15:36:26

问题


Suppose I have the following tables:

 ______________________
|       LAWSUIT        |
|______________________|
| ID                   |
| TITLE                |
|______________________|
                        \
                         \
                          \
                             ______________________
                            | PERSONS_IN_THE_CASE  |
                            |______________________|
                            | ID_LAWSUIT           |
                            | ID_PERSON            |
                            |______________________|
                          /
                         /
                        /
 ______________________
|        PERSON        |
|______________________|
| ID                   |
| NAME                 |
| TYPE                 | TYPE values = "Plantiff, Defendant, Lawyer, Judge, ..."
|______________________|

(I know that normalizing the database I could have a table for each person type, but let's stick to the actual structure)

I've subclassed the different Persons with JPA (2.0) as follows:

@Entity
@Table(name="PERSON")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "TYPE")
public abstract class Person {
@Entity
@DiscriminatorValue("Plantiff")
public class Plantiff extends Person {  
@Entity
@DiscriminatorValue("Defendant")
public class Defendant extends Person { 
@Entity
@DiscriminatorValue("Lawyer")
public class Lawyer extends Person {    

This works correctly, because I can query a single category and the filter is automatic, eg findAll on Plantiff will get all the Plantiffs of all times.

Now I'm trying to link them to the Lawsuit through the PERSONS_IN_THE_CASE @JoinTable:

@Entity
@Table(name="LAWSUIT")
public class Lawsuit {

    @Id
    Long id;

    String title;

    @OneToMany
    @JoinTable(name="PERSONS_IN_THE_CASE",
               joinColumns=@JoinColumn(name="ID_LAWSUIT", referencedColumnName="ID"),
        inverseJoinColumns=@JoinColumn(name="ID_PERSON",  referencedColumnName="ID"))
    Plantiff plantiff;


    @ManyToMany
    @JoinTable(name="PERSONS_IN_THE_CASE",
               joinColumns=@JoinColumn(name="ID_LAWSUIT", referencedColumnName="ID"),
        inverseJoinColumns=@JoinColumn(name="ID_PERSON",  referencedColumnName="ID"))
    Set<Defendant> defendants;

    ...
}

Here is where things break: the @DiscriminatorValue is not applied, it seems to be completely bypassed by the @JoinTable.

In fact, the Set<Defendant> does not contain only the defendants, but every person in the case (every record in the PERSONS_IN_THE_CASE relational table. For example, if I have a Plantiff, a Judge, two Defendants and two Lawyers, the above Set<Defendant> will contain 6 persons instead of 2).

How can I make the @DiscriminatorValue working through the @JoinTable binding ?

EDIT: I'm using Hibernate 3.6.6.Final, and (although I always try to avoid it) I'm open to vendor-specific solutions, like @ForceDiscriminator(deprecated), @DiscriminatorOptions(force=true) and so on. I've obviosuly tried before asking (without being able to make it work, though).


回答1:


There is no way in standard JPA to share a join table, and have an extra column in the join table as a type of distinguisher as to which relation it is for.

You could use a separate join table, or dig into vendor extensions that your JPA provider supports; I know that DataNucleus JPA does allow something like what you need (see this doc, for JDO, but it also works for JPA) and would expect that other providers maybe have some way of doing this - but you then make your app non-portable in terms of JPA provider.

Alternatively redesign the relations, if that is an option for your project




回答2:


In short, it seems like @DiscriminatorColumn is not meant to have your hierarchy distinguished for you. In other words, the discriminator column worked at a simple level if everything went into one list. As soon as I started trying to ask it to separate the Entities into separate lists then I stated having trouble, as you did.

I tried essentially what you described without the extra JoinColumn annotations, and I couldn't insert because the join table that was created had two separate ids in it, one for one class, one for another, and any insert could not satisfy both at the same time. With the extra annotations to control the join configuration, there was still issues. I could get things inserted, but not retrieved.

Basically, you could look at @MappedSuperclass as a solution to your design considerations. A Person would be the MappedSuperclass Entity, which would be abstract, and Lawyers, Judges, Plaintiffs, Defendants, etc., would be concrete subclasses.

@MappedSuperclass
public abstract class Content
{
   @Id @GeneratedValue private Integer  id;

   public Integer getId() {
       return id;
   }

}

and as Conrete classes ...

@Entity
public class EnglishContent extends Content {

    @Override
    public String toString() {
        return "EnglishContent:"+getId();
    }
}

and

@Entity
public class SpanishContent extends Content {

    @Override
    public String toString() {
        return "SpanishContent:"+getId();
    }
}

and something to hold them:

@Entity
public class Question {
    @Id @GeneratedValue private Integer id;

    @OneToMany(cascade=CascadeType.ALL)
    List<EnglishContent> englishContents;

    @OneToMany(cascade=CascadeType.ALL)
    List<SpanishContent> spanishContents;
    ... getters, setters, 
}

and this test works OK.

    Question q = new Question();

    SpanishContent sc = new SpanishContent();
    List<SpanishContent> spanishContents = new ArrayList<SpanishContent>();
    spanishContents.add(sc);
    q.setSpanishContents(spanishContents);

    EnglishContent ec = new EnglishContent();
    List<EnglishContent> englishContents = new ArrayList<EnglishContent>();
    englishContents.add(ec);
    q.setEnglishContents(englishContents);

    em.persist(q);

and

    Question q = em.find(Question.class, 1);
    System.out.println(q);

So, not the same classes, but it gives you separate lists, has polymorphism, and seems like a cleaner design anyway. Of course, there are more database tables, but that shouldn't be a major consideration.

Hope this helps.




回答3:


it is still ignored in hibernate 5.4.2, our work around is using the @Where annotation from hibernate, still not optimal



来源:https://stackoverflow.com/questions/35872402/why-is-discriminatorcolumn-ignored-when-using-jointable

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!