views:

290

answers:

3

Hi guys,

I'm mapping a proprietary database to Hibernate for use with Spring. In it, there are a couple of jointables that, for entity A and entity B have the following schema:

CREATE TABLE AjoinB (
  idA int not null,
  idB int not null,
  groupEnum enum ('groupC', 'groupD', 'groupE'),
  primary key(idA, idB, groupEnum)
);

As you can see, this indicates that there can be multiple A-B relationships that put them in different groups. I'd like to end up with, first line for entity A and second for entity B, the following sets

Set<B> BforGroupC, BforGroupD, BforGroupE;
Set<A> AforGroupC, AforGroupD, AforGroupE;

So far, I've only managed to put them in one set and disregard the groupEnum relationship attribute:

@ManyToMany(targetEntity=B.class, cascade={ CascadeType.PERSIST, CascadeType.MERGE } )
@JoinTable(name="AjoinB", joinColumns=@JoinColumn(name="idA"), inverseJoinColumns=@JoinColumn(name="idB") )
private Set<B> BforAllGroups;

and

@ManyToMany( mappedBy = "BforAllGroups", targetEntity = A.class )
private Set<A> AforAllGroups;

How can I make multiple sets where they belong either in groupC, groupD or groupE?

Cheers

Nik

+2  A: 

To my knowledge, Hibernate cannot use such a "discriminator" column in the way that you want. Hibernate requires a join table for each of them.

Perhaps you might be able to define additional views on the table, showing each of the groupings?

skaffman
Hi Skaffman, and thanks for your suggestion. If I define the views "CREATE VIEW viewAjoinBgroupC AS SELECT idA, idB FROM AjoinB WHERE groupEnum='groupC'", then any insert into my set will be like "insert into viewAjoinBgroupC VALUES (2,3);", thus giving me an invalid entry (2,3,'groupC'). If you have a suggestion on how to overcome this, then this is a workaround that could work. Cheers -Nik
niklassaers
A: 

I think the advise anytime you need to access a field in a link table is to make the link table an object and a hibernate entity in its own right. A would have a set of AtoB objects and AtoB would have a set of B objects. I have a simmilar situation where the link table has a user associated with the link.

select joinTable.b from A a 
left join a.AtoB joinTable
where joinTable.group = 'C'

It's not as elegant as having an implicit join done by hibernate, but it does give you the control you need.

+2  A: 

If you're considering doing this, don't. Tables are cheap nowadays what's with the economy and all, so just create one per association; it'll be so much easier.

If you're bound by a legacy database and you can't change the structure of that table I would

  1. Consider skaffman's solution first (+1, btw). Depending on your target database you may be able to write a trigger for your views that would insert adequate "discriminator" value.

  2. If the above isn't possible in your DB, another solution is to use custom SQL for CRUD operations for your collections. Keep in mind that this will NOT work (e.g. your "discriminator value" won't get applied) for complex HQL queries involving your association as part of condition. You can also mix / match this with above - e.g. use views and use custom SQL for insert / delete.

  3. If both of the above fail, go with "association as a separate entity" as suggested by framer8. That's going to be rather ugly (since we're assuming here you can't change your tables) due to composite keys and all extraneous code. It may, in fact, be impossible if any of your associations allows duplicates.

ChssPly76
It's strange that such an easy thing as properties on a relation is so hard with Hibernate, so I filed a bug on it. The work-around I'll go for is a mix of #1 and #2 in your answer. Thanks a lot for your input :-)
niklassaers