I'm trying to fetch my "Ticket" entity with my "FileData" included, but I can't get it to work and I'm completely out of ideas as of why. Others' code seems to work just fine with just what I did with my own. But whenever I fetch it, my "Ticket" object's "files" column comes back empty, no matter what.
(and yes, there's data for it in the database, so the associated column to the given ID is not null or anything like that)
My BaseEntity class includes the @Id annotation, and date created, modified, created by user etc.
Ticket entity:
package com.issue.tracker.ticket;
import com.issue.tracker.common.BaseEntity;
import com.issue.tracker.filesystem.FileData;
import com.issue.tracker.project.Project;
import jakarta.persistence.*;
import jakarta.validation.constraints.NotEmpty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.HashSet;
import java.util.Set;
@Data
@EqualsAndHashCode(callSuper = true)
@Entity
@Table(name = "tickets")
public class Ticket extends BaseEntity {
@NotEmpty
private String issueName;
@NotEmpty
private String description;
@ManyToOne
@JoinColumn(name="project_id", nullable=false)
private Project project;
//This is supposed to work but for some reason it doesn't seem to
@OneToMany(mappedBy = "ticket", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
private Set<FileData> files = new HashSet<>();
}
FileData entity:
package com.issue.tracker.filesystem;
import com.issue.tracker.common.BaseEntity;
import com.issue.tracker.ticket.Ticket;
import jakarta.persistence.*;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
@Data
@EqualsAndHashCode(callSuper = true)
@Entity
@Table(name = "file_datas")
@AllArgsConstructor
@NoArgsConstructor
public class FileData extends BaseEntity {
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name="ticket_id", nullable=false)
private Ticket ticket;
@NotEmpty
private String filePath;
@NotEmpty
private String fileName;
@NotEmpty
private String fileType;
@NotNull
private Long fileSize;
}
TicketRepository:
package com.issue.tracker.ticket;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface TicketRepository extends JpaRepository<Ticket, Long> {
List<Ticket> findAllByCreatedBy(String username);
}
TicketServiceImpl (including the commented out part where I get an empty "files" column back):
package com.issue.tracker.ticket;
import com.issue.tracker.common.RollbackOnException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Optional;
@Slf4j
@RequiredArgsConstructor
@Service
public class TicketServiceImpl implements TicketService {
private final TicketRepository ticketRepository;
@RollbackOnException
@Override
public Ticket createTicket(Ticket ticket) {
return ticketRepository.save(ticket);
}
@Override
public List<Ticket> getAllTicketsByName(String username) {
return ticketRepository.findAllByCreatedBy(username);
}
@Override
public List<Ticket> getAllTickets() {
return ticketRepository.findAll();
}
@Override
public Ticket getTicketById(Long id) {
Ticket ticket = ticketRepository.findById(id).orElseThrow(() -> new NoSuchElementException("Ticket not found"));
log.info(ticket.toString());
//this is what I get here, note that "files" is empty:
//Ticket(issueName=AAAAAAAAAA...
//description=ahdfjduafadjfhadjfhadjfhadjfhadjlfhadjfadjfhad,
//project=Project(projectName=Webshop), files=[])
return ticket;
}
}
I was curious about the SQL log and this is the hibernate magic that happens in the background:
select
t1_0.id,
t1_0.created_at,
t1_0.created_by,
t1_0.description,
t1_0.issue_name,
t1_0.modified_by,
p1_0.id,
p1_0.created_at,
p1_0.created_by,
p1_0.modified_by,
p1_0.project_name,
p1_0.updated_at,
t1_0.updated_at
from tickets t1_0 join projects p1_0 on p1_0.id=t1_0.project_id
where t1_0.id=?
select f1_0.ticket_id,
f1_0.id,
f1_0.created_at,
f1_0.created_by,
f1_0.file_name,
f1_0.file_path,
f1_0.file_size,
f1_0.file_type,
f1_0.modified_by,
f1_0.updated_at
from file_datas f1_0
where f1_0.ticket_id=?
select f1_0.ticket_id,
f1_0.id,
f1_0.created_at,
f1_0.created_by,
f1_0.file_name,
f1_0.file_path,
f1_0.file_size,
f1_0.file_type,
f1_0.modified_by,
f1_0.updated_at
from file_datas f1_0
where f1_0.ticket_id=?
My file_datas part is getting called separately, twice. I'm guessing twice because there's two rows that correspond to the given ticket_id. I've included some pictures of the data and connection between the tables.
UPDATE
It still doesn't work.
public TicketDataDto getTicketById(@PathVariable Long id) {
Ticket ticket = ticketService.getTicketById(id);
ticket.getFiles();
log.info(ticket.toString());
return modelMapper.map(ticket, TicketDataDto.class);
}
Simply calling ticket.getFiles() doesn't do anything, it's still empty.
Modifying it to
public TicketDataDto getTicketById(@PathVariable Long id) {
Ticket ticket = ticketService.getTicketById(id);
var files = ticket.getFiles();
log.info(files.toString());
return modelMapper.map(ticket, TicketDataDto.class);
}
doesn't work either. Changing the Ticket entity's fetchtype to fetch=FetchType.EAGER doesn't solve it.
UPDATE 2 Removing @Data from the Ticket entity and creating its own toString doesn't help either, same response every time.
@Override
public String toString() {
return "Ticket{" +
"issueName='" + issueName + '\'' +
", description='" + description + '\'' +
", project=" + project +
", files=" + files +
'}';
}
This toString produces:
Ticket{issueName='AAAAAAAAAAAAAAAAAAAAA', description='ahdfjduafadjfhadjfhadjfhadjfhadjlfhadjfadjfhad', project=Project(projectName=Webshop), files=[]}




Your "files" attribut is supposed to be empty because u define it like that :
fetch = FetchType.LAZYThen if u call
getFileson your retrieved ticket, it will fetch files.