# @OneToMany @JoinTable failed to lazily initialize a collection Fehler



## Schuriko (13. Jan 2019)

Ich erstelle mir gerad ein Projekt. Folgend ein Auszug daraus. Ich habe eine Entity "Project" und "File". Ein Project kann beliebig viele Files haben. Also eine OneToMany. Da ich File noch an anderer Stelle verwende verbinde ich die beiden über eine Join-Table.


```
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.Lob;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import javax.validation.constraints.Max;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;

import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.UpdateTimestamp;

@Entity
@Table(name="projects")
public class Project {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
   
    @CreationTimestamp
    private Date    created_at;
   
    @OneToOne(cascade = CascadeType.REMOVE, fetch=FetchType.EAGER)
    @JoinColumn(name="created_by")       
    private User    created_by;
   
    @UpdateTimestamp
    private Date    updated_at;
   
    @OneToOne(cascade = CascadeType.REMOVE, fetch=FetchType.EAGER)   
    @JoinColumn(name="updated_by")       
    private User    updated_by;   
   
    @NotNull
    private Boolean    published = false;
   
    @Size(min=3, max=255)
    @NotBlank       
    private String    name;

    @Size(min=3, max=10)
    private String    key;
   
    @Max(255)
    private String    symbol;
   
    private Integer    color = 0;
   
    @Lob
    private String    description;

    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
    @JoinColumn(name = "project_files")   
    private List<File> files = new ArrayList<>();
   
    public Project() {
        super();
    }
   
    public Project(@Size(min = 3, max = 255) @NotBlank String name) {
        super();
        this.name = name;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public Date getCreatedAt() {
        return created_at;
    }

    public void setCreatedAt(Date created_at) {
        this.created_at = created_at;
    }

    public User getCreatedBy() {
        return created_by;
    }

    public void setCreatedBy(User created_by) {
        this.created_by = created_by;
    }

    public Date getUpdatedAt() {
        return updated_at;
    }

    public void setUpdatedAt(Date updated_at) {
        this.updated_at = updated_at;
    }

    public User getUpdatedBy() {
        return updated_by;
    }

    public void setUpdatedBy(User updated_by) {
        this.updated_by = updated_by;
    }

    public Boolean getPublished() {
        return published;
    }

    public void setPublished(Boolean published) {
        this.published = published;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getKey() {
        return key;
    }

    public void setKey(String key) {
        this.key = key;
    }

    public String getSymbol() {
        return symbol;
    }

    public void setSymbol(String symbol) {
        this.symbol = symbol;
    }

    public Integer getColor() {
        return color;
    }

    public void setColor(Integer color) {
        this.color = color;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public List<File> getFiles() {
        return files;
    }

    public void setFiles(List<File> files) {
        this.files = files;
    }

    @Override
    public String toString() {
        return "Project [id=" + id + ", created_at=" + created_at + ", created_by=" + created_by + ", updated_at="
                + updated_at + ", updated_by=" + updated_by + ", published=" + published + ", name=" + name + ", key="
                + key + ", symbol=" + symbol + ", color=" + color + ", description=" + description + ", files=" + files
                + "]";
    }
       
}
```


```
import java.util.Date;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.Lob;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;

import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.UpdateTimestamp;

@Entity
@Table(name="files")
public class File {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
   
    @CreationTimestamp
    private Date    created_at;
   
    @OneToOne(cascade = CascadeType.REMOVE, fetch=FetchType.EAGER)
    @JoinColumn(name="created_by")       
    private User    created_by;
   
    @UpdateTimestamp
    private Date    updated_at;
   
    @OneToOne(cascade = CascadeType.REMOVE, fetch=FetchType.EAGER)   
    @JoinColumn(name="updated_by")       
    private User    updated_by;       
   
    @NotNull
    private Boolean    published = false;
   
    @Size(min=3, max=255)
    @NotBlank       
    private String    name;
   
    @Lob
    private String    description;
   
    @Size(min=3, max=255)
    @NotBlank       
    private String    filename;

    private String    type;
   
    public File() {
        super();
    }
   
    public File(@Size(min = 3, max = 255) @NotBlank String name, @Size(min = 3, max = 255) @NotBlank String filename) {
        super();
        this.name = name;
        this.filename = filename;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public Date getCreatedAt() {
        return created_at;
    }

    public void setCreatedAt(Date created_at) {
        this.created_at = created_at;
    }

    public User getCreatedBy() {
        return created_by;
    }

    public void setCreatedBy(User created_by) {
        this.created_by = created_by;
    }

    public Date getUpdatedAt() {
        return updated_at;
    }

    public void setUpdatedAt(Date updated_at) {
        this.updated_at = updated_at;
    }

    public User getUpdatedBy() {
        return updated_by;
    }

    public void setUpdatedBy(User updated_by) {
        this.updated_by = updated_by;
    }

    public Boolean getPublished() {
        return published;
    }

    public void setPublished(Boolean published) {
        this.published = published;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public String getFilename() {
        return filename;
    }

    public void setFilename(String filename) {
        this.filename = filename;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    @Override
    public String toString() {
        return "File [id=" + id + ", created_at=" + created_at + ", created_by=" + created_by + ", updated_at="
                + updated_at + ", updated_by=" + updated_by + ", published=" + published + ", name=" + name
                + ", description=" + description + ", filename=" + filename + ", type=" + type + "]";
    }   
   
   
}
```


```
import java.util.List;

import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;

import com.abado.pts.entities.File;

public interface FileRepository extends CrudRepository<File, Long> {
    @Modifying
    @Query("delete from File f where f.id in ?1")
    void deleteWithIds(List<Long> ids);
   
    @Modifying
    @Query("update File set published = ?2 where id = ?1")
    void setPublished(Long id, Boolean publish);

    @Modifying
    @Query("update File set published = ?2 where id in ?1")
    void publishWidthIds(List<Long> ids, Boolean published);

}
```


```
import java.util.List;

import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;

import com.abado.pts.entities.Project;

public interface ProjectRepository extends CrudRepository<Project, Long> {
   
    @Modifying
    @Query("delete from Project p where p.id in ?1")
    void deleteWithIds(List<Long> ids);
   
    @Modifying
    @Query("update Project set published = ?2 where id = ?1")
    void setPublished(Long id, Boolean publish);
   
    @Modifying
    @Query("update Project set published = ?2 where id in ?1")
    void publishWidthIds(List<Long> ids, Boolean published);
}
```


```
iimport java.util.Optional;

import javax.transaction.Transactional;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.abado.pts.entities.Language;
import com.abado.pts.entities.Project;
import com.abado.pts.repositories.LanguageRepository;
import com.abado.pts.repositories.ProjectRepository;

@Service
@Transactional
public class ProjectService {
   
    @Autowired
    ProjectRepository projectRepository;
   
    public Project save(Project project) {
        return projectRepository.save(project);
    }

    public Optional<Project> findById(Long id) {
        return projectRepository.findById(id);
    }
}
```


```
import static org.junit.Assert.*;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Optional;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import com.abado.pts.entities.File;
import com.abado.pts.entities.Project;
import com.abado.pts.repositories.FileRepository;
import com.abado.pts.repositories.ProjectRepository;

@RunWith(SpringRunner.class)
@SpringBootTest
public class ProjectServiceTest {
   
    @Autowired
    ProjectService projectService;
   
    @Autowired
    ProjectRepository projectRepository;

    @Autowired
    FileRepository fileRepository;
   
    @Before
    public void setUp() throws Exception {
    }

    /**
     * test save without files
     */
    @Test
    public void testSaveWithoutFiles() {
        String  projectnameValue = "Project 1";
        Project project = new Project(projectnameValue);
       
        projectService.save(project);
       
        Optional<Project> foundProject = projectService.findById(project.getId());
       
        assertTrue(foundProject.isPresent());
        assertNotNull(foundProject.get().getCreatedAt());
        assertNotNull(foundProject.get().getUpdatedAt());
       
        // clear
        projectRepository.deleteAll();
        fileRepository.deleteAll();
    }
   
    /**
     * test save with files
     */
    @Test
    public void testSaveWithUnstoredFiles() {
        String  projectnameValue = "Project 1";
        List<File> files = new ArrayList<>();
        Project project = new Project(projectnameValue);
       
        files.add(new File("name1", "filename1"));
        files.add(new File("name2", "filename2"));
        files.add(new File("name3", "filename3"));

        assertEquals(3, files.size());
       
        project.setFiles(files);
        assertEquals(3, project.getFiles().size());
       
        assertNotNull(projectService.save(project));
       
        Optional<Project> foundProject = projectService.findById(project.getId());
       
        assertTrue(foundProject.isPresent());
        assertEquals("File Count: " + foundProject.get().getFiles().size(), 3, foundProject.get().getFiles().size());

        // clear
        projectRepository.deleteAll();
        fileRepository.deleteAll();
    }
   
}
```

Beim Test erhalte ich folgende Fehlermeldung


> org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: Project.files, could not initialize proxy - no Session
> at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:597)
> at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:216)
> at org.hibernate.collection.internal.AbstractPersistentCollection.readSize(AbstractPersistentCollection.java:160)
> ...


Ich verstehe nur nicht so ganz was ich falsch mache.


----------



## httpdigest (13. Jan 2019)

Das Problem ist, dass du auf eine noch nicht initialisierte (weil lazy - @OneToMany werden per Default lazy nachgeladen) Collection Project.getFiles() außerhalb einer Transaktion innerhalb der Testmethode ProjectServiceTest.testSaveWithUnstoredFiles() zugreifst. Deine Transaktion erstreckt sich nur über den Service, aber eben nicht über deinen Unit-Test. Deshalb kann Hibernate die Datenbank nicht mehr fragen, um die Files eines Projektes nachzuladen.
Entweder, du lässt deine Transaktion über deinen Test erstrecken, oder du nutzt @OneToMany(fetch=EAGER).


----------



## Schuriko (14. Jan 2019)

httpdigest hat gesagt.:


> Das Problem ist, dass du auf eine noch nicht initialisierte (weil lazy - @OneToMany werden per Default lazy nachgeladen) Collection Project.getFiles() außerhalb einer Transaktion innerhalb der Testmethode ProjectServiceTest.testSaveWithUnstoredFiles() zugreifst. Deine Transaktion erstreckt sich nur über den Service, aber eben nicht über deinen Unit-Test. Deshalb kann Hibernate die Datenbank nicht mehr fragen, um die Files eines Projektes nachzuladen.
> Entweder, du lässt deine Transaktion über deinen Test erstrecken, oder du nutzt @OneToMany(fetch=EAGER).


Danke es funktioniert. Ich habe die @OneToMany jetzt wie folgt


> @OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true)


----------

