【发布时间】:2014-06-27 07:54:28
【问题描述】:
如果这太愚蠢或不完整,我很抱歉。
我想进行一次查询,一次连接所有表。
@NamedQuery(name="User.findByLogin",
query="SELECT u FROM User u " +
"left outer join fetch u.userInfo ui " +
"left outer join fetch u.freeEvents fe " +
"left outer join fetch u.paidEvents pe " +
"left outer join fetch fe.action fea " +
"left outer join fetch pe.action pea " +
"where u.login = :login")
它可以工作(没有错误,没有警告,生成了 sql),并且 SQL 很好,并且在 mysql 控制台中检索了所有适当的数据。但在那之后,它发出许多请求以通过 id 查找操作,并且看起来 hibernate 不知道它已经获取了所有需要的数据或者不知道如何处理它。
具有两个表的所有其他类似联接均有效且按预期工作。
顺便说一下,freeEvent 和paidEvent 是@Inheritance(strategy=InheritanceType.SINGLE_TABLE),它们的区别在于“rate_type”列。我尝试了急切和懒惰的提取,以及休眠 @Fetch 注释。
sql 本身:
select * #---lots of fields here, all valid
from Users user0_ left outer join UserInfos userinfo1_ on user0_.`user_info_id`=userinfo1_.id
left outer join Events freeevents2_ on user0_.id=freeevents2_.`user_id` and freeevents2_.rate_type=1
left outer join FreeActions freeaction4_ on freeevents2_.`action_id`=freeaction4_.`id`
left outer join Events paidevents3_ on user0_.id=paidevents3_.`user_id` and paidevents3_.rate_type=2
left outer join PaidActions paidaction5_ on paidevents3_.`action_id`=paidaction5_.`id` where user0_.`login`='testuser'
问题:问题出在哪里?我的类是否注释不佳,或者这是正常的休眠行为,在哪里可以找到解决方案?
实体:(没有 getter、setter 和未被任何人映射的字段)
@Entity
@Table(name="Events")
@PersistenceUnit(name="default")
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name="rate_type", discriminatorType=DiscriminatorType.INTEGER)
public class AbstractEvent {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long Id;
@ManyToOne(fetch=FetchType.LAZY)
private models.User user;
@Column(name="rate_type", insertable=false, updatable=false)
private byte rateType;
}
@Entity
@DiscriminatorValue(RateTypeHelper.RATE_TYPE_FREE) //it just a constant of type integer == 1
@PersistenceUnit(name="default")
public class FreeEvent extends models.events.AbstractEvent {
@OneToOne(cascade=CascadeType.PERSIST, fetch=FetchType.LAZY)
@JoinColumn(name="`action_id`")
private FreeAction action;
public FreeAction getAction() {
return action;
}
public void setAction(FreeAction action) {
this.action = action;
}
}
@Entity
@DiscriminatorValue(RateTypeHelper.RATE_TYPE_PAID)
@PersistenceUnit(name="default")
public class PaidEvent extends models.events.AbstractEvent {
@OneToOne(cascade=CascadeType.PERSIST, fetch=FetchType.LAZY)
@JoinColumn(name="`action_id`")
private PaidAction action;
public PaidAction getAction() {
return action;
}
public void setAction(PaidAction action) {
this.action = action;
}
}
注意:这里的抽象动作现在不使用了。它没有任何字段或方法。只是为了未来的需要而空的班级。
@Entity
@Table(name="FreeActions")
@PersistenceUnit(name="default")
@NamedQueries({
@NamedQuery(name="FreeAction.findByUserId",
query="select a from FreeAction a " +
"left outer join fetch a.event e " +
"where e.user = :user_id")
})
public class FreeAction extends AbstractAction {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name="`id`")
private Long Id;
@OneToOne(mappedBy="action", fetch=FetchType.LAZY)
private models.events.FreeEvent event;
}
@Entity
@Table(name="PaidActions")
@PersistenceUnit(name="default")
@NamedQueries({
@NamedQuery(name="PaidAction.findByUserId",
query="select a from PaidAction a " +
"left outer join fetch a.event e " +
"where e.user = :user_id")
})
public class PaidAction extends AbstractAction {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name="`id`")
private Long Id;
@OneToOne(mappedBy="action", fetch=FetchType.LAZY)
private models.events.PaidEvent event;
}
@Entity
@Table(name="Users")
@PersistenceUnit(name="default")
@NamedQueries({
@NamedQuery(name="findFullUserById",
query="select u from User u "+
"left outer join fetch u.userInfo ui " +
"where u.id = :id"),
@NamedQuery(name="User.findByLoginPassword",
query="SELECT u FROM User u left outer join fetch u.userInfo ui " +
"where u.login = :login and u.password = :password"),
@NamedQuery(name="User.findByLogin",
query="SELECT u FROM User u " +
"left outer join fetch u.userInfo ui " +
"left outer join fetch u.freeEvents fe " +
"left outer join fetch u.paidEvents pe " +
"left outer join fetch fe.action fea " +
"left outer join fetch pe.action pea " +
"where u.login = :login")
})
public class User {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name="id")
private Long Id;
@OneToMany(fetch=FetchType.LAZY)
@JoinColumn(name="`user_id`")
private Set<FreeEvent> freeEvents;
@OneToMany(fetch=FetchType.LAZY)
@JoinColumn(name="`user_id`")
private Set<PaidEvent> paidEvents;
@OneToOne(cascade=CascadeType.PERSIST, fetch=FetchType.LAZY)
@JoinColumn(name="`user_info_id`")
private UserInfo userInfo;
}
@Entity
@Table(name="UserInfos")
@PersistenceUnit(name="default")
public class UserInfo {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name="id")
private Long Id;
@OneToOne(mappedBy="userInfo")
private User user;
}
【问题讨论】:
-
你可以发布你的实体
-
是否只是未获取的操作引用? JPA/JPQL 不支持嵌套连接获取,因此 Hibernate 可能只是忽略了 fe.action fea 和 pe.action pea 连接的 Fetch 部分,而不是抛出验证类型异常。除了更改映射之外,其他提供程序还有其他方法来支持嵌套获取,例如查询提示 - Hibernate 可能有类似的非 JPA 方法。
标签: java sql hibernate jpa join