- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我有一个 spring boot 应用程序,它使用 Hibernate 作为 ORM 和 DGS framework作为 graphql 引擎。我一直在努力寻找初始化延迟加载集合的正确方法。我有以下情况:
application.properties
# The below has been set to false to get rid of the anti-pattern stuff it introduces
spring.jpa.open-in-view=false
...
@Entity
public class User {
@Id
@GeneratedValue
private UUID id;
@OneToMany(mappedBy = "user", fetch = FetchType.LAZY)
private List<Article> articles;
...
}
@Entity
public class Article {
@Id
@GeneratedValue
private UUID id;
@ManyToOne(optional = false, fetch = FetchType.LAZY)
private User user;
...
}
我的 User
数据 getter 看起来像这样:
@DgsComponent
public class UserDataFetcher {
@Autowired
private UserService userService;
@DgsQuery
public User getUserById(@InputArgument UUID id) {
return userService.findById(id);
}
...
}
我的 UserService
看起来像这样:
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserRepository userRepository;
@Override
public User findById(UUID id) {
return userRepository.findById(id).orElseThrow(DgsEntityNotFoundException::new);
}
...
}
现在,我只想在用户在 graphql 查询中请求时从数据库初始化/加载我的文章集合。为此,我为我的文章创建了一个子解析器,它仅在用户在查询中请求文章时执行。我的 UserDataFetcher
开始看起来像这样:
@DgsComponent
public class UserDataFetcher {
@Autowired
private UserService userService;
@DgsQuery
public User getUserById(@InputArgument UUID id) {
return userService.findById(id);
}
@DgsData(parentType = "User", field = "articles")
public List<Article> getArticle(DgsDataFetchingEnvironment dfe) {
User user = dfe.getSource();
Hibernate.initialize(user.getArticles());
return user.getArticles();
}
...
}
但是,上面开始抛出异常,告诉我 Hibernate 无法为上述请求找到打开的 session 。这是有道理的,因为没有任何东西,所以我在我的子解析器上放了一个 @Transactional
,它开始看起来像这样:
@DgsComponent
public class UserDataFetcher {
@Autowired
private UserService userService;
@DgsQuery
public User getUserById(@InputArgument UUID id) {
return userService.findById(id);
}
@DgsData(parentType = "User", field = "articles")
@Transactional
public List<Article> getArticle(DgsDataFetchingEnvironment dfe) {
User user = dfe.getSource();
Hibernate.initialize(user.getArticles());
return user.getArticles();
}
...
}
但是,上面的方法也没有用。我也尝试将此 @Transactional
移动到我的服务层,但即使那样它也不起作用,并且抛出了相同的异常。经过深思熟虑,我发现(也许)Hibernate.initialize(...)
仅在我在初始事务中调用它时才有效,该事务首先为我获取了我的用户。意思是,它对我没有用,因为我的用例是非常用户驱动的。我只想在我的用户要求时得到它,并且它总是在父事务之外的我的应用程序的其他部分。
我正在寻找除以下之外的解决方案:
@DgsData(parentType = "User", field = "articles")
@Transactional
public List<Article> getArticle(DgsDataFetchingEnvironment dfe) {
User user = dfe.getSource();
List<Article> articles = articlesRepository.getArticlesByUserId(user.getUserId);
return articles;
}
我不赞成上述解决方案,因为我觉得这是通过尝试自己解决关系而不是让 hibernate 自己来解决而未充分利用 ORM 本身。 (如果我这样想错了,请纠正我)
User
实体以使用 FetchMode.JOIN
。@Entity
public class User {
@Id
@GeneratedValue
private UUID id;
@OneToMany(mappedBy = "user", fetch = FetchType.LAZY)
@Fetch(FetchMode.JOIN)
private List<Article> articles;
...
}
这与告诉 hibernate 无论如何都急切加载下面的集合是一样的。我也不想要这个。
将 spring.jpa.open-in-view=false
设置为 spring.jpa.open-in-view=true
。也不赞成这样做,因为这只是 LazyInitializationExceptions
的创可贴。
通过在请求的整个生命周期中保持 session 打开来让您忘记 LazyInitializationException
的任何其他解决方案。
最佳答案
请注意,此答案假定可以使用 Spring Data JPA。
有帮助的可以full dynamic usage of EntityGraphs
Entity Graphs give us a possibility to define fetch plans and declare whichrelations (attributes) have to be queried from the database.
你可以做类似的事情
productRepository.findById(1L, EntityGraphUtils.fromAttributePaths(“article, “comments”));
并根据用户选择将所有必要的参数(关系)传递给 EntityGraphUtils.fromAttributePaths
方法。这使我们有可能只获取必要的数据。
其他资源:
关于java - 如何在以正确方式获取的事务之外初始化延迟加载的集合?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69143733/
我是一名优秀的程序员,十分优秀!