简体   繁体   中英

Hibernate annotation mapping to joined table with composite key

I have an entity, that i'd like to join OneToOne with a table with a composite key (Omitting getters/setters):

@Entity
@Table(name = "parent")
public class Parent {
  @Id
  private String parentId;
  @Column(name = "data")
  private String data;
  @OneToOne
  private Child child;
}

And:

@Entity
@IdClass(ChildKey.class)
@Table(name = "child")
public class Child{
  @Id
  private String parentId;
  @Id
  private String username;
  @Column(name = "data")
  private String childData;
}

public class ChildKey implements Serializable {
  private String parentId;
  private String username;
}

Parent does not have a notion of the 'username' field in the Child entity. I need to pass this in as criteria. In the DB, the primary key of child is on parentId and username.

If I don't specify a JoinColumn, hibernate attempts to map using fields child_username and child_parentId. If I specify only one Joincolumn, I get a broken mapping. If I specify both JoinColumns, I have no column on parent to specify.

How can I map this class and pass in the username as criteria? (it is coming from authentication data) Or how can I do this in a different way if I'm off track.

You might be able to use a Derived Identity.

The Parent class would remain the same; but you would specify a @OneToOne mapping back to the child's parent and the Child and ChildKey classes would look like this:

@Entity
@IdClass(ChildKey.class)
@Table(name = "child")
public class Child{
  @Id
  @OneToOne(mappedBy="child")
  private Parent parent;
  @Id
  private String username;
  @Column(name = "data")
  private String childData;
}

public class ChildKey implements Serializable {
  private String parent; // name matches name of the @Id field and type matches type of Parent @Id field
  private String username; // name and type match those of the @Id field
}

Derived identity is discussed in JPA 2.1 spec, section 2.4.1.

What I ended up doing was defining a @Filter on the Child class, like so:

@Entity
@IdClass(ChildKey.class)
@Table(name = "child")
@FilterDef(name = "usernameFilter", parameters = {
        @ParamDef( name = "username", type="string")
})
public class Child { ... }

On the Parent class, I annotated the collection with a reference to the filter:

@OneToMany(fetch = FetchType.EAGER)
@JoinColumn(name = "parentId")
@Filter(name="usernameFilter", condition = "username = :username")
private List<Child> children;

Finally, in my DAO, I parameterized the filter by name like so:

Filter filter = currentSession().enableFilter("usernameFilter");
filter.setParameter("username", user.getUsername());

Doing this resulted in the exact SQL I had in mind, which is an additional clause in the JOIN criteria with a variable:

SELECT 
    ...
FROM
    parent this_
        LEFT OUTER JOIN
    child child_ ON this_.parentId = child_.parentId
        AND child_.username = ?

I might not have been clear about what end result I was looking for in my original question. Posting this answer in case it helps someone else.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM