Java Spring中JPA存储库界面投影的最佳实践?

Java Spring中JPA存储库界面投影的最佳实践?,java,spring-data-jpa,nhibernate-projections,Java,Spring Data Jpa,Nhibernate Projections,我想知道是否有人能对我目前正在玩的模式给出反馈?它涉及到让一个实体实现一个DTO接口,该接口也在JpaRepository接口中使用(作为投影)——对于同一实体——以返回具有特定列的查询结果。DTO接口还有默认方法,允许实体和DTO代理的任何实例具有类似的行为 我想回答的问题是,这种模式是否有任何缺点,例如性能,可能会妨碍人们在生产中使用它。我还想听听其他人是如何使用JpaRepositories查询特定数据字段的。下面我有一个代码示例,演示了我正在使用的模式 public interface

我想知道是否有人能对我目前正在玩的模式给出反馈?它涉及到让一个实体实现一个DTO接口,该接口也在JpaRepository接口中使用(作为投影)——对于同一实体——以返回具有特定列的查询结果。DTO接口还有默认方法,允许实体和DTO代理的任何实例具有类似的行为

我想回答的问题是,这种模式是否有任何缺点,例如性能,可能会妨碍人们在生产中使用它。我还想听听其他人是如何使用JpaRepositories查询特定数据字段的。下面我有一个代码示例,演示了我正在使用的模式

public interface InstructorDTO {
    String getFirstName();
    String getLastName();

    default String getFullName() {
        return getFirstName() + ' ' + getLastName();
    }
}

@Entity
public class Instructor implements InstructorDTO {
    @Id
    @GeneratedValue(strategy= GenerationType.AUTO)
    private int id;

    @Column(name="first_name")
    private String firstName;

    @Column(name="last_name")
    private String lastName;

    @Column(unique = true)
    private String email;

    @Override
    public String getFirstName() {
        return this.firstName;
    }

    @Override
    public String getLastName() {
        return this.lastName;
    }

    ...remaining getters and setters
}

@Repository
public interface InstructorRepository extends JpaRepository<Instructor, Integer> {

    <S> S findById(int id, Class<S> type);

    <T> Collection<T> findByEmail(String email, Class<T> type);
}


public class SomeClass {
    @Autowired
    InstructorRepository instructorRepository;

    public void someMethod {
        int id = 1;

        // Returns proxy
        InstructorDTO instructor1 = instructorRepository.findById(id, InstructorDTO.class);

        // Returns Instructor Object
        Instructor instructor2 = instructorRepository.findOne(id);

        System.out.println(instructor1.getFullName()); // returns John Doe
        System.out.println(instructor2.getFullName()); // returns John Doe
    }
}
公共接口{
字符串getFirstName();
字符串getLastName();
默认字符串getFullName(){
返回getFirstName()+“”+getLastName();
}
}
@实体
公共课堂讲师实施讲师培训{
@身份证
@GeneratedValue(策略=GenerationType.AUTO)
私有int-id;
@列(name=“first_name”)
私有字符串名;
@列(name=“last_name”)
私有字符串lastName;
@列(唯一=真)
私人字符串电子邮件;
@凌驾
公共字符串getFirstName(){
返回这个.firstName;
}
@凌驾
公共字符串getLastName(){
返回this.lastName;
}
…剩下的接受者和接受者
}
@存储库
公共接口讲师报告扩展了JpaRepository{
S findById(int-id,类类型);
收集findByEmail(字符串电子邮件,类类型);
}
公共类{
@自动连线
讲师或报告员讲师或报告员;
公开无效法{
int-id=1;
//返回代理
InstructorTo instructor1=instructorRepository.findById(id,InstructorTo.class);
//返回讲师对象
讲师讲师2=讲师报告.findOne(id);
System.out.println(instructor1.getFullName());//返回John Doe
System.out.println(instructor2.getFullName());//返回John Doe
}
}

相比之下,此解决方案没有缺点。如果只需要几列,使用DTO而不是实体要好得多

因为如果只在SQL上使用DTO,将生成用于选择数据的语句。其中,如果您使用实体,则可能会加载急切或延迟获取的关系,这可能会导致n+1选择问题

只有当您真的希望您的实体扩展DTO时,才有问题。我认为那没有道理

两项建议

  • 不要使用@GeneratedValue(策略=GenerationType.AUTO)。为什么你能在这里找到

  • 您可以删除@Repository,因为您的扩展来自JpaRepository


感谢您的快速回复!我会确保在编写代码时牢记您的建议。目前,我需要实体和DTO,因为我将编写API来检索实体中的所有信息,以及一些只需要几列的信息。另一个原因是我将在一个项目中继续其他人的工作,并且使用的数据库当前由实体类构建。你能给我举一些使用DTO的例子吗?你想举什么例子?DTO只是一个包含一些字段的类或接口。仍然不清楚您所说的“如果您只需要几列,最好使用DTO而不是实体。”我使用DTO接口仅选择名字和姓氏。让JpaRepository接口中的方法返回常规对象的原因是,我可以传递其他以其他字段为目标的DTO。哦,你是说使用查询参数吗?e、 g.@Query(“从讲师p中选择p.firstname,p.lastname,其中p.firstname=?和p.lastname=?”)讲师到findInfo(字符串firstname,字符串lastname);不我们可以聊聊吗?