据我了解,JPA实体图应用于加载原本会延迟加载的实体。我的问题是,我使用实体图来获取引用的LAZY实体,但是当我尝试在Transactional
方法之外访问那些字段时,我得到了 LazyInitializationException 。这是我尝试过的方法。
这是定义实体图的表。
UserTable.java
@Entity
@Table(name = "NF_USER")
@Inheritance(strategy = InheritanceType.JOINED)
@NamedEntityGraph(name = "user-entity-graph-with-messages-and-profile-photos",
attributeNodes = {
@NamedAttributeNode(value = "messagesSent"),
@NamedAttributeNode(value = "messagesReceived"),
@NamedAttributeNode(value = "profilePhotos")
})
public class UserTable {
private static final long serialVersionUID = 1L;
@Id
@Column(name = "USER_ID", nullable = false)
private Long userId;
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY, targetEntity = ProfilePhotoTable.class)
private Set<ProfilePhotoTable> profilePhotos = new HashSet<>();
@OneToMany(mappedBy = "sender", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
private Set<MessageTable> messagesReceived = new HashSet<>();
@OneToMany(mappedBy = "receiver", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
private Set<MessageTable> messagesSent = new HashSet<>();
这是我用来获取具有相应实体图的实体的类。
UserQueryBuilder.java
@Service
public class UserQueryBuilder {
private final EntityManager entityManager;
private TypedQuery<E> query;
public UserQueryBuilder(EntityManager entityManager) {
this.entityManager = Objects.requireNonNull(entityManager);
}
public Optional<E> singleResult() {
E entity = null;
try {
entity = query.getSingleResult();
} catch (NoResultException e) {
// ignore when no result
}
return Optional.ofNullable(entity);
}
public UserQueryBuilder withMessagesAndProfilePhotos() {
this.query = query.setHint("javax.persistence.loadgraph", entityManager.getEntityGraph("user-entity-graph-with-messages-and-profile-photos"));
return this;
}
public UserQueryBuilder findById(long id) {
this.query = entityManager
.createQuery("SELECT e FROM UserTable e WHERE e.userId = :userId", UserTable.class)
.setParameter("userId", id);
return this;
}
}
这是我的带有Transactional方法的DAO类。
UserDAO.java
@Service
public class UserDAO {
@Inject
private UserQueryBuilder userQueryBuilder;
@Transactional(propagation = Propagation.REQUIRED)
public UserTable findById(long userId) {
final UserTable user = userQueryBuilder
.findById(userId)
.withMessagesAndProfilePhotos()
.singleResult()
.orElseThrow(() -> new NonExistingEntityException(
String.format("User with ID=%d not found.", userId)));
return user;
}
}
这是我的业务类,尝试访问用户的 LAZY 个人资料照片属性(应该已经通过实体图获得)。
@Service
public class MessageService {
@Inject
private UserDAO userDAO;
public void readAllForUser(long userId) {
final UserTable user = userDAO.findById(userId);
user.getProfilePhotos(); // THIS THROWS LAZY INITIALIZATION EXCEPTION
}
所以问题是当我从数据库中加载UserTable
并尝试在Transactional方法之外使用它的惰性字段时,我得到了LazyInitializationException。如果我使用JPA实体图加载惰性实体,为什么会发生这种情况?