Spring Data JPA 排除特定 RequestMapping 的属性
Spring Data JPA exclude properties for specific RequestMapping
考虑到 PetClinic Res 的经典示例 API,我有 2 个 REST 调用:
- 获取 /petclinic/owners
- 获取/petclinic/owners/[SOME_ID]
首先调用 return 所有所有者(详细),然后调用 return 特定所有者的详细信息。
在这两种情况下,每个所有者对象都包含所有者的基本详细信息以及 宠物 列表,每个 宠物 还包含 访问次数
如果我想 return 列出没有宠物的所有者并访问我的 findAll(第一个 API)电话的详细信息,最好的方法是什么?第二次通话的完整详细信息??
我探索了自定义序列化程序 实现,但我不想在实体级别应用它。如果我使用 jackson 手动准备 JSON 它仍然会进行数据库调用!!我基本上想在第一次调用 REST 时避免不必要的数据库提取
我认为如果您真的想这样做,您需要的是 returning Object 而不是确切的 Owner 实体。
如果您希望 DB 层也高效,它只获取您需要的属性,您应该创建一个函数,它接受一个包含值的列表是您需要的属性,并且该函数将 return 一个对象和然后将其与您的 API 一起发送。
所以在你的情况下,它会是这样的。
//DAO
public List<Object> findAll(List<String> fieldsNeeded) {
String hql = "SELECT ";
for (String field: fieldsNeeded) {
hql += field + " ";
}
hql += "FROM //your table name";
// create query and all those stuff;
// return the result
}
//controller
@GetMapping("/petclinic/owners")
public List<Object> getOwners(//your parameters) {
// (lets skip service layer)
// then you need to prepare the list of needed properties
// including checking if the properties do exsit in the table etc...
// which also returns an object;
List<String> fieldsNeeded = new ArrayList<String>();
// add all the fieldnames;
return ownerDao.findAll(fieldsNeeded);
}
此外,如果您有一个包含大量属性的巨大 table,您应该使用 StringBuilder 中的 .append() 函数更改 "hql += ...",并且如果所需的属性数量太多大,您应该告诉函数不要获取传递的属性,而是获取未传递的属性。
所以我才发现您实际上不能 return 使用 REST 的对象。
因此,如果您需要发送 jsut 一个对象,我建议您在获得 DAO 层的结果后在服务层添加一个注入步骤,您将对象中的所有字段设置到实体中,它应该可以工作很好。
您需要将数据库对象与您 return 分开。由于宠物在 LAZY OneToMany 关联后面,因此当您在 findAll 中获得列表时,它们不会被提取...但是当您将实体对象传递到将(大概)调用每个 getter 的序列化库时,它们会被提取给定的对象。
所以现在要么你以某种方式修改序列化过程,这样它就不会调用错误的 getters 并触发获取......或者你制作一个映射器,将实体转换为仅包含所需字段的 DTO,并且序列化它们。您可以使用现有的映射库来简化该过程(即 mapstruct)。
您甚至可以将这些 DTO 作为 API 模型的应用程序的适当部分 - 将前端 API 与数据库分开,以便您可以更轻松地对其进行修饰更改(您不需要的字段不要存储在数据库中,重命名不会破坏您的 JPQL,可能会生成文档)
考虑到 PetClinic Res 的经典示例 API,我有 2 个 REST 调用:
- 获取 /petclinic/owners
- 获取/petclinic/owners/[SOME_ID]
首先调用 return 所有所有者(详细),然后调用 return 特定所有者的详细信息。
在这两种情况下,每个所有者对象都包含所有者的基本详细信息以及 宠物 列表,每个 宠物 还包含 访问次数
如果我想 return 列出没有宠物的所有者并访问我的 findAll(第一个 API)电话的详细信息,最好的方法是什么?第二次通话的完整详细信息??
我探索了自定义序列化程序 实现,但我不想在实体级别应用它。如果我使用 jackson 手动准备 JSON 它仍然会进行数据库调用!!我基本上想在第一次调用 REST 时避免不必要的数据库提取
我认为如果您真的想这样做,您需要的是 returning Object 而不是确切的 Owner 实体。 如果您希望 DB 层也高效,它只获取您需要的属性,您应该创建一个函数,它接受一个包含值的列表是您需要的属性,并且该函数将 return 一个对象和然后将其与您的 API 一起发送。 所以在你的情况下,它会是这样的。
//DAO
public List<Object> findAll(List<String> fieldsNeeded) {
String hql = "SELECT ";
for (String field: fieldsNeeded) {
hql += field + " ";
}
hql += "FROM //your table name";
// create query and all those stuff;
// return the result
}
//controller
@GetMapping("/petclinic/owners")
public List<Object> getOwners(//your parameters) {
// (lets skip service layer)
// then you need to prepare the list of needed properties
// including checking if the properties do exsit in the table etc...
// which also returns an object;
List<String> fieldsNeeded = new ArrayList<String>();
// add all the fieldnames;
return ownerDao.findAll(fieldsNeeded);
}
此外,如果您有一个包含大量属性的巨大 table,您应该使用 StringBuilder 中的 .append() 函数更改 "hql += ...",并且如果所需的属性数量太多大,您应该告诉函数不要获取传递的属性,而是获取未传递的属性。
所以我才发现您实际上不能 return 使用 REST 的对象。 因此,如果您需要发送 jsut 一个对象,我建议您在获得 DAO 层的结果后在服务层添加一个注入步骤,您将对象中的所有字段设置到实体中,它应该可以工作很好。
您需要将数据库对象与您 return 分开。由于宠物在 LAZY OneToMany 关联后面,因此当您在 findAll 中获得列表时,它们不会被提取...但是当您将实体对象传递到将(大概)调用每个 getter 的序列化库时,它们会被提取给定的对象。
所以现在要么你以某种方式修改序列化过程,这样它就不会调用错误的 getters 并触发获取......或者你制作一个映射器,将实体转换为仅包含所需字段的 DTO,并且序列化它们。您可以使用现有的映射库来简化该过程(即 mapstruct)。
您甚至可以将这些 DTO 作为 API 模型的应用程序的适当部分 - 将前端 API 与数据库分开,以便您可以更轻松地对其进行修饰更改(您不需要的字段不要存储在数据库中,重命名不会破坏您的 JPQL,可能会生成文档)