1

I've got a strange behaviour with a JPA class hierarchy using a single table. Basically I have two entities EntityMapA and EntityMapB which both extend EntityMap. The discriminator value is 'ENTITY_TYPE' and it is A for EntityMapA and B for EntityMapB. Somehow I get Objects of type EntityMapA where the discriminator value is set to 'B'!

I am using Hibernate 3.3 as the JPA provider.

Here is the code:

@Entity
@Table(name="ENTITY_MAP")
@DiscriminatorColumn(name = "ENTITY_TYPE")
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
public class EntityMap implements Serializable {

    /**
     *
     */
    private static final long serialVersionUID = 1L;
    private Long entityMapId;

    //This is a ID of another entity we map to. It is a different entity type depending on 
    //The subclass. For EntityMapA it would map to EntityA and for EntityMapB it would map   
    // to EntityB
    private Long entityId;


    private String discriminator;

    @Id
    @GeneratedValue(strategy = IDENTITY)
    @Column(name = "ENTITY_MAP_ID", unique = true, nullable = false)
    public Long getEntityMapId() {
        return entityMapId;
    }
    public void setEntityMapId(Long EntityMapId) {
        this.entityMapId = entityMapId;
    }


    @Column(name="ENTITY_TYPE",insertable=false,updatable=false)
    public String getDiscriminator() {
        return discriminator;
    }
    public void setDiscriminator(String discriminator) {
        this.discriminator = discriminator;
    }

    @Column(name="ENTITY_ID",insertable=false,updatable=false)
    public Long getEntityId() {
        return entityId;
    }
    public void setEntityId(Long entityId) {
        this.entityId = entityId;
    }

    //there are other common fields in here which are left out    
}


@Entity
@DiscriminatorValue("A")
public class EntityMapA extends EntityMap {

    /**
     *
     */
    private static final long serialVersionUID = -8709307036005000705L;

    private EntityA entityA;

    public static final String DISCRIMINATOR = "A";

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "ENTITY_ID", nullable = false)
    @NotNull
    public EntityA getEntityA() {
        return entityA;
    }

    public void setEntityA(EntityA entityA) {
        this.entityA = entityA;
    }

}



@Entity
@DiscriminatorValue("B")
public class EntityMapB extends EntityMap {

    /**
     *
     */
    private static final long serialVersionUID = -8709307036005000705L;

    public static final String DISCRIMINATOR = "B";

    private EntityB entityB;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "ENTITY_ID", nullable = false)
    @NotNull
    public EntityB getEntityB() {
        return entityB;
    }

    public void setEntityB(EntityB entityB) {
        this.entityB = entityB;
    }
}

And then finally I have a mapping in EntityA:

    @OneToMany(cascade=CascadeType.ALL,fetch = FetchType.LAZY, mappedBy = "entityA")
    public List<EntityMapA> getEntityMaps() {
        return entityMaps;
    }

    public void setEntityMaps(List<EntityMapA> entityMaps) {
        this.entityMaps = entityMaps;
    }

Now I have a ENTITY_MAP row with ENTITY_TYPE = "B" and ENTITY_ID = "12345" There are both a EntityA with the id "12345" and a EntityB with the same ID "12345".

Now when I load EntityA with the id "12345" is has one entry in the getEntityMaps() of type EntityMapA but the discriminator value on that EntityMapA is 'B'.

What is going wrong here? Why is a row with the discriminator 'B' mapped to a EntityMapA entity?

Is it because I map the EntityId twice (once with @Column(name="ENTITY_TYPE",insertable=false,updatable=false) on the parent class and then again per JoinColumn to the actual entity?

UPDATE Btw, the EntityMapA listed in the collection on EntityA is never really created. When you try to load the entity you get an exception telling you that that entity doesn't exists. So looks like a bug in Hibernate to me.

1 Answer 1

2

The problem is that you use the same column to map two different associations. AFAIK, this is not supported.

And it's actually a good thing, because it's much cleaner to use two separate columns to refer to different things. It allows defining an FK constraint on those columns, for example, which isn't possible with your current solution since the column holds IDs of EntityA or EntityB depending on the row.

Sign up to request clarification or add additional context in comments.

2 Comments

I still think this is a bug. A row with the discriminator set to B should never create an EntityMapA.
Its not a bug in Hibernate, its a questionable mapping as already pointed out to you. The correct mapping is to map the association on EntityMap as an EntityMap. You can use covariant return types on EntityMapA and EntityMapB if you want.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.