views:

222

answers:

1

I have a mapped entity with a property "latestHistory", which is mapped through a join table, like:

class Record {

  @OneToOne(cascade = { CascadeType.MERGE, CascadeType.PERSIST, CascadeType.REMOVE }, fetch = FetchType.LAZY, optional = true)
  @JoinTable(name = "latest_history_join_view", joinColumns = { @JoinColumn(name = "record_id") }, inverseJoinColumns = { @JoinColumn(name = "history_id") })
  @AccessType("field")
  public History getLatestHistory() { ... }
}

The mapping works correctly when I call myRecord.getLatestHistory().

I have a complex native SQL query, which returns a batch of Records, and joins on the History for each record using the join table. I want to return Record entites from the query, and have the History objects populated in the result. My attempt looks like this:

StringBuffer sb = new StringBuffer();
sb.append("select {r.*}, {latestHistory.*}");
sb.append(" from record r");
sb.append(" left join latest_history_join_view lh on lh.record_id = r.record_id");
sb.append(" left join history latestHistory on latestHistory.history_id = lh.history_id");
SQLQuery query = session.createSQLQuery(sb.toString());
query.addEntity("r", Record.class).addJoin("latestHistory", "r.latestHistory");

When I do this, it generates a query like:

select 
   r.record_id, r.name..., 
   r_1.history_id,  --this part is wrong; there is no such alias r_1 
   latestHistory.history_id, latestHistory.update_date, ...
 from record r
 left join latest_history_join_view lh on lh.record_id = r.record_id
 left join history latestHistory on latestHistory.history_id = lh.history_id

How can I get it to join correctly and fetch my association, without messing up the select list?

[Update: some of the approaches that I've tried:

select {r.*}, {latestHistory.*} -> SQL error, generates a wrong column name "r_1.history_id"
select {r.*}, {anyOtherEntityAssociatedToR.*} -> wrong column name (as above)
select {r.*}, {r.history_id}, {latestHistory.*} -> hibernate error, r has no history_id column
select r.*, lh.history_id as history_id -> this works (though hackish), but doesn't accomplish the join
select r.*, lh.history_id as history_id, latestHistory.* -> appears correct, but results in column name collisions
select r.*, {latestHistory.*} -> error when hibernate looks for a nonexistent column in the result set (this happens if there is any alias at all in the select list)

It doesn't seem to make a lot of difference whether I use addEntity(...) or addJoin(...), as long as the leftmost (root) entity is added using addEntity.

]

+1  A: 

I'm thinking you actually need to specify full path for your latestHistory in select e.g.

select {r.*}, {r.latestHistory.*}

otherwise Hibernate gets confused and attempts to treat it as a separate entity. The other option is to not specify injected aliases in select at all which should work for a single "to-one" relationship so long as column order in your tables matches property order in your entities.

I've never tried this on @OneToOne over association table, though.

ChssPly76
Thanks, Chss - I'm trying out r.latestHistory.*. How would I do it without specifying injected aliases at all?
RMorrisey
As long as column / property order matches, you should be able to do `select r.*, latestHistory.*` - that is, using SQL aliases rather than injected aliases.
ChssPly76
Using {r.latestHistory.*}, I get: org.hibernate.QueryException: No column name found for property [latestHistory.*] for alias [r]
RMorrisey
I think one-to-one over association table is the source of the problems here; try doing it with no injected aliases but if that doesn't work you may have to resort to selecting them as independent entities (http://docs.jboss.org/hibernate/stable/core/reference/en/html/querysql.html#d0e13732). So, basically, your original select but with second `addEntity()` instead of `addJoin()`. As I said, I've never done this mapping over association table, so I'm not speaking from experience here :-)
ChssPly76