我有用户实体:
@ToString
@Data
@Entity
@Table(name = "users")
@NamedEntityGraph(name = "UserWithItems",
attributeNodes = {
@NamedAttributeNode("items"),
@NamedAttributeNode("roles")
})
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "name")
private String name;
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL)
private List<Item> items;
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL)
private List<Role> roles;
}
项目:
@ToString(exclude = "user")
@Data
@Entity
@Table(name = "items")
public class Item {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "name")
private String name;
@ManyToOne
@JoinColumn(name = "user_id", referencedColumnName = "id", nullable = false)
private User user;
}
角色:
@ToString
@Data
@Entity
@Table(name = "roles")
public class Role {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "name")
private String name;
@ManyToOne
@JoinColumn(name = "user_id", referencedColumnName = "id", nullable = false)
private User user;
}
我想为用户加载项目和角色。我使用@NamedEntityGraph
。这是我的资料库:
@EntityGraph(value = "UserWithItems", type = EntityGraph.EntityGraphType.LOAD)
@Query("select u from User u where u.id = ?1 and u.name =?2")
User getOneById(Long id, String name);
但是我得到一个错误:
Caused by: org.hibernate.loader.MultipleBagFetchException: cannot simultaneously fetch multiple bags: [com.example.egerload.entity.User.roles, com.example.egerload.entity.User.items]
at org.hibernate.loader.BasicLoader.postInstantiate(BasicLoader.java:75) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
at org.hibernate.loader.hql.QueryLoader.<init>(QueryLoader.java:108) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:212) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:143) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:119) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:85) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
at org.hibernate.query.internal.AbstractProducedQuery.makeQueryParametersForExecution(AbstractProducedQuery.java:1350) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
at org.hibernate.query.internal.AbstractProducedQuery.doList(AbstractProducedQuery.java:1539) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
at org.hibernate.query.internal.AbstractProducedQuery.list(AbstractProducedQuery.java:1505) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
... 41 common frames omitted
答案 0 :(得分:0)
您可以将您的 "UserWithItems" @NamedEntityGraph
拆分为两个 @NamedEntityGraph
,从而产生两个查询,如 Hibernate throws MultipleBagFetchException - cannot simultaneously fetch multiple bags - answer of Vlad Mihalcea 中所述。
用户
@ToString
@Data
@Entity
@Table(name = "users")
@NamedEntityGraphs(
{
@NamedEntityGraph(
name = "UserWithItems",
attributeNodes = {
@NamedAttributeNode("items")
}
),
@NamedEntityGraph(
name = "UserWithRoles",
attributeNodes = {
@NamedAttributeNode("roles")
}
),
}
)
public class User {
...
}
我假设您有一个存储库类。例如 extends JpaRepository
。在额外的方法上使用每个 NamedEntityGraph
。 (我省略了 name 条件和 @Query("...")。id 条件应该就足够了,因为它是用户的标识符。@Query("...") 不需要。)
用户存储库
public interface UserRepository extends JpaRepository<User, Long> {
@EntityGraph(value = "UserWithItems", type = EntityGraph.EntityGraphType.LOAD)
Optional<User> getOneWithItemsById(Long id);
@EntityGraph(value = "UserWithRoles", type = EntityGraph.EntityGraphType.LOAD)
Optional<User> getOneWithRolesById(Long id);
....
}
最后,您可以在服务中调用这两种方法。
用户服务
public interface UserService {
Optional<User> readById(Long id);
}
UserServiceImpl
@Service
public class UserServiceImpl implements UserService {
private final UserRepository userRepository;
public UserServiceImpl(UserRepository userRepository) {
this.userRepository = userRepository;
}
@Override
@Transactional
public Optional<User> readById(Long id) {
// Load user with items into persistence contex
userRepository.getOneWithItemsById(id);
// Load user with roles into persistence context
// (There is only one user instance by id within the persistence context)
return userRepository.getOneWithRolesById(id);
}
}