简体   繁体   English

Hibernate - 惰性初始化失败

[英]Hibernate - lazy initialize failure

I am trying to load an entity from the database with hibernate but I get the following error我正在尝试使用 hibernate 从数据库加载实体,但出现以下错误

failed to lazily initialize a collection of role: package.entities.machinegroup.MachineGroup.users

This is my MachineGroup entity:这是我的 MachineGroup 实体:

public class MachineGroup {
    @Id
    @GeneratedValue(strategy= GenerationType.AUTO, generator = "machine_groups_seq")
    @SequenceGenerator(name = "machine_groups_seq", allocationSize = 1, initialValue = 2)
    @Column(name = "id")
    private long id;
    @Column(name = "name")
    private String name;
    @Column(name = "creation_time")
    private Date creationTime;
    @Column(name = "is_official")
    private boolean official;
    @OneToOne(cascade = CascadeType.ALL)
    @JoinColumn(name = "machine_properties_id", nullable = false)
    private ContinuousIntegrationProperties defaultContinuousIntegrationProperties;
    @ManyToMany(fetch = FetchType.EAGER)
    @JoinTable(name = "machine_groups_to_users",
            joinColumns = @JoinColumn(name = "machine_group_id"),
            inverseJoinColumns = @JoinColumn(name = "user_id"))
    private Set<User> users = new HashSet<>();
 @JoinTable(name = "machine_groups_to_versions",
            joinColumns = @JoinColumn(name = "machine_group_id"),
            inverseJoinColumns = @JoinColumn(name = "version_id"))
    private Set<Version> versions = new HashSet<>();
}

This is the entity that I am trying to fetch:这是我要获取的实体:

public class MachineGroupToVersion {
    @Id
    @GeneratedValue(strategy= GenerationType.AUTO, generator = "machine_groups_to_versions_seq")
    @SequenceGenerator(name = "machine_groups_to_versions_seq", allocationSize = 1)
    @Column(name = "id")
    private long id;
    @ManyToOne
    @JoinColumn(name = "machine_group_id", nullable = false)
    private MachineGroup machineGroup;
    @ManyToOne
    @JoinColumn(name = "version_id", nullable = false)
    private Version version;
}

Why does it say that it fails lazily initialize the collection users within MachinGroup if I have explicitly said "fetch = FetchType.EAGER"?如果我已经明确地说“fetch = FetchType.EAGER”,为什么它说它无法延迟初始化 MachinGroup 中的集合用户?

UPDATE:更新:

User class用户 class

public class User {
    @Id
    @GeneratedValue(strategy= GenerationType.AUTO, generator = "users_seq")
    @SequenceGenerator(name = "users_seq", allocationSize = 1, initialValue = 2)
    @Column(name = "ID")
    private long id;
    @Column(name = "username")
    private String username;
    @Column(name = "creation_time")
    private Date creationTime;
    @Column(name = "role")
    private String role;
    @Column(name = "email")
    private String email;
    @ManyToMany(mappedBy = "users", cascade = CascadeType.MERGE)
    private Set<MachineGroup> machineGroups = new HashSet<>();
    @OneToMany(mappedBy = "owner")
    private Set<Campaign> campaigns = new HashSet<>();
}

UPDATE 2:更新 2:

full stacktrace:完整的堆栈跟踪:

Could not write JSON: failed to lazily initialize a collection of role: .entities.user.User.machineGroups, could not initialize proxy - no Session; nested exception is com.fasterxml.jackson.databind.JsonMappingException: failed to lazily initialize a collection of role: .entities.user.User.machineGroups, could not initialize proxy - no Session (through reference chain: java.util.ArrayList[0]->.entities.machinegrouptoversion.MachineGroupToVersionDTO[\"machineGroup\"]->.entities.machinegroup.MachineGroup[\"users\"]->org.hibernate.collection.internal.PersistentSet[0]->.entities.user.User[\"machineGroups\"])

UPDATE 3:更新 3:

MachineGroupToVersionService MachineGroupToVersionService

 @Transactional(transactionManager = "primaryTransactionManager", propagation= Propagation.REQUIRED, readOnly=true, noRollbackFor=Exception.class)
    public List<MachineGroupToVersionDTO> getByMachineGroupName(String mgName) {
        List<MachineGroupToVersionDTO> mgtvl = new ArrayList<>();
        Optional<MachineGroup> mg = machineGroupService.getByName(mgName);
        if(mg.isPresent())
            mgtvl = machineGroupToVersionRepository.findByMachineGroup(mg.get()).stream()
                    .map(this::convertToDto).collect(Collectors.toList());
        return mgtvl;
    }

    private MachineGroupToVersionDTO convertToDto(MachineGroupToVersion mgtv) {
        MachineGroupToVersionDTO machineGroupToVersionDTO = new MachineGroupToVersionDTO();
        machineGroupToVersionDTO.setMachineGroup(mgtv.getMachineGroup());
        machineGroupToVersionDTO.setVersion(mgtv.getVersion());
        machineGroupToVersionDTO.setCreationTime(mgtv.getCreationTime());
        machineGroupToVersionDTO.setState(mgtv.getState());
        machineGroupToVersionDTO.setTestedTime(mgtv.getTestedTime());
        return machineGroupToVersionDTO;

    }

You probably are trying to fetch lazy attributes without oppening a hibernate transaction session (which is required to instantiate lazy collections through hibernate proxy).您可能试图在不打开 hibernate 事务 session 的情况下获取惰性属性(这是通过 hibernate 代理实例化惰性 collections 所必需的)。 Add org.springframework.transaction.annotation.Transactional(readOnly = true) annotation to the method which you are using to fetch your MachineGroup collection.org.springframework.transaction.annotation.Transactional(readOnly = true)注释添加到您用于获取MachineGroup集合的方法。

Edit: You're probably facing cyclic fetching issue, while fetching MachineGroup by Name on service method, it fetches the MachineGroup and also, all the users by eager mode ( @ManyToMany(fetch = FetchType.EAGER) ), which have a List of MachineGroup too.编辑:您可能面临循环获取问题,在服务方法上按名称获取 MachineGroup 时,它会通过急切模式( @ManyToMany(fetch = FetchType.EAGER) )获取MachineGroup以及所有用户,其中包含一个列表机器组也是。

In your DTO conversion method, you are setting a MachineGroup , that have a list of users, and to set this list of users, each user must have a list of MachineGroup again, which is lazily fetched by default, and that is the exact breakpoint of the thrown exception:在您的 DTO 转换方法中,您正在设置一个MachineGroup ,它有一个用户列表,要设置这个用户列表,每个用户必须再次有一个MachineGroup列表,默认情况下是延迟获取的,这就是确切的断点抛出的异常:

Could not write JSON: failed to lazily initialize a collection of role: .entities.user.User.machineGroups, could not initialize proxy - no Session; nested exception is com.fasterxml.jackson.databind.JsonMappingException: failed to lazily initialize a collection of role: .entities.user.User.machineGroups, could not initialize proxy - no Session (through reference chain: java.util.ArrayList[0]->.entities.machinegrouptoversion.MachineGroupToVersionDTO[\"machineGroup\"]->.entities.machinegroup.MachineGroup[\"users\"]->org.hibernate.collection.internal.PersistentSet[0]->.entities.user.User[\"machineGroups\"])

If you need to retrieve the information of the many-to-many table machine_groups_to_users I suggest you to create an entity with a composite primary key and remove the List of MachineGroup from your user entity.如果您需要检索多对多表machine_groups_to_users的信息,我建议您创建一个具有复合主键的实体,并从您的用户实体中删除MachineGroup列表。

The problem is that in your MachineGroupToVersionDTO the machineGroup your are setting, the MachineGroup#users collection contains at least one User referring to some MachineGroup through User#machineGroups , that is not initialized.问题是,在您设置的MachineGroupToVersionDTO中, MachineGroup#users集合至少包含一个User通过User#machineGroups machineGroup某个MachineGroup ,但未初始化。 You can either try to join fetch all of that or sprinkle some @JsonIgnore annotations around but I doubt this will work for you as you will probably want to serialize the machine groups of a user for some other endpoints.您可以尝试 join fetch all that or sprinkle some @JsonIgnore annotations 但我怀疑这对你有用,因为你可能想要为其他一些端点序列化用户的机器组。 So in the end, the only option you have (in my opinion) is that you introduce DTOs all the way and do not use any entities in your DTO models.所以最后,你唯一的选择(在我看来)是你一直引入 DTO 并且不在你的 DTO 模型中使用任何实体。

I think this is a perfect use case forBlaze-Persistence Entity Views .我认为这是Blaze-Persistence Entity Views的完美用例。

I created the library to allow easy mapping between JPA models and custom interface or abstract class defined models, something like Spring Data Projections on steroids.我创建了这个库,以允许在 JPA 模型和自定义接口之间轻松映射或抽象 class 定义的模型,类似于类固醇上的 Spring 数据投影。 The idea is that you define your target structure(domain model) the way you like and map attributes(getters) via JPQL expressions to the entity model.这个想法是,您按照自己喜欢的方式定义目标结构(域模型),并通过 JPQL 表达式将 map 属性(getter)定义为实体 model。

A DTO model for your use case could look like the following with Blaze-Persistence Entity-Views:对于您的用例,DTO model 对于 Blaze-Persistence 实体视图可能如下所示:

@EntityView(MachineGroupToVersion.class)
public interface MachineGroupToVersionDto {
    @IdMapping
    Long getId();
    String getState();
    Date getCreationTime();
    Date getTestedTime();
    VersionDto getVersion();
    MachineGroupDto getMachineGroup();

    @EntityView(Version.class)
    interface VersionDto {
        @IdMapping
        Long getId();
        String getName();
    }
    @EntityView(MachineGroup.class)
    interface MachineGroupDto {
        @IdMapping
        Long getId();
        String getName();
        Date getCreationTime();
        Set<UserDto> getUsers();
    }
    @EntityView(User.class)
    interface UserDto {
        @IdMapping
        Long getId();
        String getUsername();
    }
}

Querying is a matter of applying the entity view to a query, the simplest being just a query by id.查询是将实体视图应用于查询的问题,最简单的就是通过 id 进行查询。

MachineGroupToVersionDto a = entityViewManager.find(entityManager, MachineGroupToVersionDto.class, id);

The Spring Data integration allows you to use it almost like Spring Data Projections: https://persistence.blazebit.com/documentation/entity-view/manual/en_US/index.html#spring-data-features Spring 数据集成允许您几乎像 Spring 数据投影一样使用它: https://persistence.blazebit.com/documentation/entity-view/manual/en_US/index.html#spring-data-features

Page<MachineGroupToVersionDto> findAll(Pageable pageable);

The best part is, it will only fetch the state that is actually necessary!最好的部分是,它只会获取实际需要的 state!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Hibernate 用投影初始化惰性场 - Hibernate initialize lazy field with projection 在hibernate中初始化所有延迟加载的集合 - Initialize all lazy loaded collections in hibernate 延迟加载和Hibernate.initialize();的问题 - Issue with lazy loading and Hibernate.initialize(); JPA和Hibernate初始化非延迟集合错误 - JPA and Hibernate initialize Non Lazy Collections Error Hibernate延迟初始化-无法延迟初始化集合 - Hibernate lazy initialization - failed to lazily initialize a collection 休眠延迟异常无法初始化代理-无会话 - hibernate lazy exception could not initialize proxy - no Session 什么是 Spring 框架或 Hibernate 上下文中的延迟初始化以及为什么我的代码给我一个“未能延迟初始化错误”? - What is lazy initialize in context with Spring Framework or Hibernate and why my code is giving me a “failed to lazy initialize error”? Java Hibernate,无法初始化延迟加载,但希望忽略这些字段 - Java Hibernate, Failed to Initialize lazy load but want to ignore those fields 休眠延迟初始化问题:LazyInitializationException:无法延迟初始化角色集合 - hibernate lazy initialization issue: LazyInitializationException: failed to lazily initialize a collection of role 在同一会话中出现异常后,休眠无法初始化惰性实体 - hibernate could not initialize lazy entity after exception in same session
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM