我正在尝试熟悉spring和jpa。首先,有一个表格 anime_details 包含动漫的详细信息。由于它具有多种类型,因此db有另一个名为 gen 的表。中间表还包含多对多关系条目。当我通过ID查询任何动漫时,它应该返回动漫的详细信息以及流派。
它确实返回一个对象,其中包含动漫的详细信息和Genre对象的列表(符合预期)。但是我想要的是限制将从Genre对象中获取的列。例如,仅id或仅id和name(以防其他列)。
AnimeDetails
@Getter
@Setter
@Entity
@Table(name = "anime_details")
public class AnimeDetails {
@Id
@SequenceGenerator(name = "animeDetailsSeq", sequenceName =
"anime_details_id_seq",
allocationSize = 1)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator =
"animeDetailsSeq")
private Integer id;
private String name;
private Integer episodes;
private Date started;
private Date ended;
private String status;
@ManyToMany
@JoinTable(
name = "anime_genre",
joinColumns = @JoinColumn(name = "details_id", referencedColumnName = "id"),
inverseJoinColumns = @JoinColumn(name = "genre_id", referencedColumnName = "id"))
@JsonManagedReference
private List<Genre> genres;
protected AnimeDetails() {
}
}
类型
@Data
@Entity
@Table(name = "genre")
public class Genre {
@Id
@SequenceGenerator(name = "genreSeq", sequenceName = "genre_id_seq",
allocationSize = 1)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "genreSeq")
private Integer id;
private String name;
@ManyToMany(mappedBy = "genres")
List<AnimeDetails> animes;
protected Genre() {
}
}
预期有效载荷
{
"id": 2,
"name": "Your Name",
"episodes": 1,
"started": "2016-08-25T18:00:00.000+0000",
"ended": "2016-08-25T18:00:00.000+0000",
"status": "Completed",
"genres": [
{
"id": 5,
"name": "Drama"
},
{
"id": 10,
"name": "Supernatural"
}
]
}
现在,我得到结果并手动逐一获取列并将其设置在DTO中。但这并不高效,因为数据库查询已经获取了比所需更多的数据。 是否有任何特定的注释/属性/ jpql来减少它?
答案 0 :(得分:1)
Indeed一直在寻找针对同一问题的正确解决方案,因为您指出它正在造成性能问题,因为APP和DB之间存在大量无用的数据负载。想象一下,不仅可能有一个查询,而且还有更多查询,并且您需要一个全局优化解决方案...
Spring DATA首先不支持此操作,因此它会引导您进行手动配置并在DTO参考上进行设置。如果您使用的是自定义对象,并使用构造函数把它返回到JPQL内,或者使用本机查询,返回List<Object>
并再次手动将数据映射回您的实际对象(即最有效但不优雅的解决方案
link中提供了更多信息,但请尝试检查两个答案的详细信息。
另一件事是,当您使用下面的hibernate(提供自定义映射器)时,您始终可以编写自定义HQL(not jpql),设置适当的DAO,连接EntityManager或直接连接EntityManager。 SessionFactory(这违反了抽象的JPA契约,但您可以利用休眠提供的全部功能),然后返回相同的对象,但仅包含所需的列。
第二点示例:
import javax.persistence.EntityManager;
import org.hibernate.query.Query;
import org.hibernate.transform.Transformers;
public CustomEntity getEntity(){
Query<CustomEntity> q = (Query<CustomEntity>) entityManager.createQuery("select
e.id,e.name from CustomEntity e where e.name = 'parameter'");
q.setResultTransformer(Transformers.aliasToBean(CustomEntity.class));
CustomEntity entity = (CustomEntity) q.getSingleResult();
return name;
}
注意CustomEntity
是数据库中的一个受管实体Bean /表,只是将本示例放在您可能需要实现的目标上。
尝试过
Spring boot 2.0.5.RELEASE
Spring Data 2.0.5.RELEASE
Hibernate-core 5.2.17.Final
答案 1 :(得分:0)
我今天尝试了另一种解决方案。让我们先看一下代码。
类型
@Data
@Entity
@Table(name = "genre")
public class Genre {
@Id
@SequenceGenerator(name = "genreSeq", sequenceName = "genre_id_seq",
allocationSize = 1)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "genreSeq")
private Integer id;
private String name;
@ManyToMany
@JoinTable(
name = "anime_genre",
joinColumns = @JoinColumn(name = "genre_id", referencedColumnName = "id"),
inverseJoinColumns = @JoinColumn(name = "details_id", referencedColumnName = "id"))
List<AnimeIdentity> animes;
protected Genre() {
}
}
AnimeIdentity
@Getter
@Setter
@Entity
@Table(name = "anime_details")
public class AnimeIdentity {
@Id
@SequenceGenerator(name = "animeDetailsSeq", sequenceName =
"anime_details_id_seq",
allocationSize = 1)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator =
"animeDetailsSeq")
private Integer id;
private String name;
protected AnimeIdentity() {};
}
Hibernate进行的查询
Hibernate: select genre0_.id as id1_2_0_, genre0_.name as name2_2_0_ from genre genre0_ where genre0_.id=?<br>
Hibernate: select animes0_.genre_id as genre_id2_1_0_, animes0_.details_id as details_1_1_0_, animeident1_.id as id1_0_1_, animeident1_.name as name2_0_1_ from anime_genre animes0_ inner join anime_details animeident1_ on animes0_.details_id=animeident1_.id where animes0_.genre_id=?
随时向我展示此解决方案的优缺点。对我来说,如果我的需要仅限于此,这是一个很好的解决方案。但是,在使用不同类型的查询的情况下,越来越多的实体pojos将是一项繁琐的任务。