Search code examples
spring-dataspring-repositories

Spring Data Repository: What is the managed type?


For my intention the JavaDoc for org.springframework.data.repository.Repository is kind of imprecise on the generic parameter <T>. It says:

@param the domain type the repository manages

Okay.

Suppose we have these entities:

@Entity
@Table
public class Parent {
    @Id
    private Long id;

    @Getter
    @OrderBy
    @OneToMany(mappedBy = "parent")
    private Set<Children> children;
}

@Entity
@Table
public class Children {
    @Id
    private Long id;

    @OneToOne
    @JoinColumn(name = "parent_id", nullable = false)
    private Parent parent;
}

If all children for a parent are queried which repository is the correct one?

public interface ParentRepository extends Repository<Parent, Long> {
    // IntelliJ Warning: 'Children' domain type or valid projection interface expected here
    @Query("SELECT children FROM Parent WHERE id = ?1")
    List<Children> getChildrenByParentId(Long parentId);
}

public interface ChildrenRepository extends Repository<Children, Long> {
    @Query("SELECT children FROM Parent WHERE id = ?1")
    List<Children> getChildrenByParentId(Long parentId);
}

What about this additional query?

@Query("SELECT parent.children FROM Parent parent LEFT JOIN parent.children children WHERE parent.id = ?1 ORDER BY children.id")
List<Children> getOrderedChildrenByParentId(Long parentId);

As it is working no matter which repository is used my interest is more why ParentRepository or ChildrenRepository is the correct one.

After skimming through the documentation: https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#reference the ParentRepository seems more correct - although the IntelliJ warning.


Solution

  • If you create an interface:

    public interface ParentRepository extends Repository<Parent, Long>
    

    The parameter Parent is used to generate the methods like findAll findOne etc. to return the correct type and the parameter Long is used as the primary key type.

    If you do:

    @Query("SELECT parent.children FROM Parent parent LEFT JOIN parent.children children WHERE parent.id = ?1 ORDER BY children.id")
    List<Children> getOrderedChildrenByParentId(Long parentId);
    

    You are absolutely free what parameter types and what return type you want to use. So it doesn't matter where you put the method with the @Query annotation.