pue*_*elo 12 spring hibernate spring-boot graphql graphql-java
我目前正在将我的REST服务器迁移到GraphQL(至少部分).大部分工作已经完成,但我偶然发现了这个问题,我似乎无法解决这个问题:在Graphql查询中使用FetchType.LAZY的OneToMany关系.
我正在使用:https: //github.com/graphql-java/graphql-spring-boot 和 https://github.com/graphql-java/graphql-java-tools进行集成.
这是一个例子:
实体:
@Entity
class Show {
private Long id;
private String name;
@OneToMany
private List<Competition> competition;
}
@Entity
class Competition {
private Long id;
private String name;
}
Run Code Online (Sandbox Code Playgroud)
架构:
type Show {
id: ID!
name: String!
competitions: [Competition]
}
type Competition {
id: ID!
name: String
}
extend type Query {
shows : [Show]
}
Run Code Online (Sandbox Code Playgroud)
解析器:
@Component
public class ShowResolver implements GraphQLQueryResolver {
@Autowired
private ShowRepository showRepository;
public List<Show> getShows() {
return ((List<Show>)showRepository.findAll());
}
}
Run Code Online (Sandbox Code Playgroud)
如果我现在使用此(简写)查询查询端点:
{
shows {
id
name
competitions {
id
}
}
}
Run Code Online (Sandbox Code Playgroud)
我得到:
org.hibernate.LazyInitializationException:懒得初始化一个角色集合:Show.competitions,无法初始化代理 - 没有Session
现在我知道为什么会出现这个错误以及它意味着什么,但我真的不知道应该为此修复.我不想让我的热衷于急切地获取所有关系,因为这会否定GraphQL的一些优点.我可能需要寻找解决方案的任何想法?谢谢!
我解决了它,我应该更仔细地阅读graphql-java-tools库的文档.除了GraphQLQueryResolver解决基本查询,我还需要一个GraphQLResolver<T>我的Show班级,看起来像这样:
@Component
public class ShowResolver implements GraphQLResolver<Show> {
@Autowired
private CompetitionRepository competitionRepository;
public List<Competition> competitions(Show show) {
return ((List<Competition>)competitionRepository.findByShowId(show.getId()));
}
}
Run Code Online (Sandbox Code Playgroud)
这告诉库如何解析Show类中的复杂对象,并且仅在最初查询请求包含Competition对象时使用.新年快乐!
编辑:这里要求的是使用自定义执行策略的另一种解决方案.我正在使用graphql-spring-boot-starter和graphql-java-tools:
我首先定义一个GraphQL配置,如下所示:
@Configuration
public class GraphQLConfig {
@Bean
public Map<String, ExecutionStrategy> executionStrategies() {
Map<String, ExecutionStrategy> executionStrategyMap = new HashMap<>();
executionStrategyMap.put("queryExecutionStrategy", new AsyncTransactionalExecutionStrategy());
return executionStrategyMap;
}
}
Run Code Online (Sandbox Code Playgroud)
在哪里AsyncTransactionalExecutionStrategy定义如下:
@Service
public class AsyncTransactionalExecutionStrategy extends AsyncExecutionStrategy {
@Override
@Transactional
public CompletableFuture<ExecutionResult> execute(ExecutionContext executionContext, ExecutionStrategyParameters parameters) throws NonNullableFieldWasNullException {
return super.execute(executionContext, parameters);
}
}
Run Code Online (Sandbox Code Playgroud)
这将查询的整个执行放在同一个事务中.我不知道这是否是最佳解决方案,并且它在错误处理方面也有一些缺点,但您不需要以这种方式定义类型解析器.
我更喜欢的解决方案是在Servlet发送响应之前打开事务。通过此小代码更改,您的LazyLoad将可以正常工作:
import javax.servlet.Filter;
import org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
/**
* Register the {@link OpenEntityManagerInViewFilter} so that the
* GraphQL-Servlet can handle lazy loads during execution.
*
* @return
*/
@Bean
public Filter OpenFilter() {
return new OpenEntityManagerInViewFilter();
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2102 次 |
| 最近记录: |