JPA EntityGraph在事务外引发LazyInitializationException

时间:2019-03-05 19:23:56

标签: java spring hibernate jpa

据我了解,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实体图加载惰性实体,为什么会发生这种情况?

0 个答案:

没有答案