Spring JPA 将分页添加到@ManyToMany
Spring JPA add pagination to @ManyToMany
在我当前的项目中,我使用 JPA 和 Hibernate 来处理我的数据库层。
我的一个实体与其自身具有多对多关系,使用 @ManyToMany
和 @JoinTable
注释效果很好。
我的问题是系统要求我为实体添加分页支持。我在网上搜索了一个解决方案,但我找到的最接近解决方案的东西适用于不同的用例,其中关系存在于 2 个实体之间(而不是一个实体本身)。
这是实体的重要部分 class:
package iob.data;
import iob.data.primarykeys.InstancePrimaryKey;
import iob.logic.exceptions.instance.InvalidBindingOperationException;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import lombok.ToString;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.IdClass;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import java.util.Date;
import java.util.HashSet;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
@RequiredArgsConstructor
@Entity
@Table(name = "INSTANCES")
@IdClass(InstancePrimaryKey.class)
public class InstanceEntity {
//<editor-fold desc="Primary key">
@Id
// The index would be generated from a sequence named "INSTANCES_SEQUENCE"
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "INSTANCES_SEQUENCE")
// Here we create that sequence, and define it to be updated every insertion (allocationSize = 1).
@SequenceGenerator(name = "INSTANCES_SEQUENCE", sequenceName = "INSTANCES_SEQUENCE", allocationSize = 1)
private long id;
@Id
@NonNull
private String domain;
//</editor-fold>
//<editor-fold desc="Many to Many relation">
// Define a new table that would store the references
@JoinTable(name = "INSTANCES_TO_INSTANCES",
// The main columns for this attribute are the parent's primary key which is constructed from domain and id
inverseJoinColumns = {@JoinColumn(name = "PARENT_ID", referencedColumnName = "id"),
@JoinColumn(name = "PARENT_DOMAIN", referencedColumnName = "domain")},
// The referenced columns for this attribute are the child's primary key which is also constructed from domain and id
joinColumns = {@JoinColumn(name = "CHILD_ID", referencedColumnName = "id"),
@JoinColumn(name = "CHILD_DOMAIN", referencedColumnName = "domain")})
// Declare the parent's side of the relation
@ManyToMany(fetch = FetchType.LAZY)
private Set<InstanceEntity> parentInstances = new HashSet<>();
// Declare the children's size of the relation, and define that it is related to the parentInstances
@ManyToMany(mappedBy = "parentInstances", fetch = FetchType.LAZY)
private Set<InstanceEntity> childInstances = new HashSet<>();
//</editor-fold>
public void addParent(InstanceEntity parent) {
if (this.equals(parent))
throw new InvalidBindingOperationException("Cannot assign parent to himself");
parentInstances.add(parent);
}
public void addChild(InstanceEntity child) {
if (this.equals(child))
throw new InvalidBindingOperationException("Cannot assign child to himself");
childInstances.add(child);
}
@Override
public int hashCode() {
return Objects.hash(id, domain);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
InstanceEntity entity = (InstanceEntity) o;
return id == entity.id && domain.equals(entity.domain);
}
}
到目前为止,我尝试(可能天真地)为 parentInstance
编写 getter 并传递给它一个 Pagable
对象(因为它适用于 derived-queries
,所以值得shot ) 但显然它什么也没做。
我能想到的唯一解决方案是删除关系,然后手动创建它(使用另一个实体创建 table 并添加一个新的 PagingAndSortingRepository
来检索相关实例,然后转换他们在服务中 InstanceEntity
。
那么,如何为 parentInstances
和 childInstances
添加分页支持?
我在一些 中找到了解决方案。和分页无关,但还是解决了我的问题
所以我的解决方案是将以下功能添加到我的 PagingAndSortingRepository
界面:
Page<InstanceEntity> findDistinctByParentInstancesIn(@Param("parent_instances") Set<InstanceEntity> parentInstances, Pageable pageable);
然后调用它是:
InstanceEntity ie = new InstanceEntity();
ie.setDomain(parentDomain);
ie.setId(Long.parseLong(parentId));
instancesDao.findDistinctByParentInstancesIn(Collections.singleton(ie), PageRequest.of(page, size));
老实说,我不确定 how/why 它是否有效。 IntelliJ IDEA 在存储库界面 Expected parameter types: Collection<Set<InstanceEntity>>
.
中给我一个错误
所以如果有人有解释,我会很高兴听到。
在我当前的项目中,我使用 JPA 和 Hibernate 来处理我的数据库层。
我的一个实体与其自身具有多对多关系,使用 @ManyToMany
和 @JoinTable
注释效果很好。
我的问题是系统要求我为实体添加分页支持。我在网上搜索了一个解决方案,但我找到的最接近解决方案的东西适用于不同的用例,其中关系存在于 2 个实体之间(而不是一个实体本身)。
这是实体的重要部分 class:
package iob.data;
import iob.data.primarykeys.InstancePrimaryKey;
import iob.logic.exceptions.instance.InvalidBindingOperationException;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import lombok.ToString;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.IdClass;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import java.util.Date;
import java.util.HashSet;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
@RequiredArgsConstructor
@Entity
@Table(name = "INSTANCES")
@IdClass(InstancePrimaryKey.class)
public class InstanceEntity {
//<editor-fold desc="Primary key">
@Id
// The index would be generated from a sequence named "INSTANCES_SEQUENCE"
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "INSTANCES_SEQUENCE")
// Here we create that sequence, and define it to be updated every insertion (allocationSize = 1).
@SequenceGenerator(name = "INSTANCES_SEQUENCE", sequenceName = "INSTANCES_SEQUENCE", allocationSize = 1)
private long id;
@Id
@NonNull
private String domain;
//</editor-fold>
//<editor-fold desc="Many to Many relation">
// Define a new table that would store the references
@JoinTable(name = "INSTANCES_TO_INSTANCES",
// The main columns for this attribute are the parent's primary key which is constructed from domain and id
inverseJoinColumns = {@JoinColumn(name = "PARENT_ID", referencedColumnName = "id"),
@JoinColumn(name = "PARENT_DOMAIN", referencedColumnName = "domain")},
// The referenced columns for this attribute are the child's primary key which is also constructed from domain and id
joinColumns = {@JoinColumn(name = "CHILD_ID", referencedColumnName = "id"),
@JoinColumn(name = "CHILD_DOMAIN", referencedColumnName = "domain")})
// Declare the parent's side of the relation
@ManyToMany(fetch = FetchType.LAZY)
private Set<InstanceEntity> parentInstances = new HashSet<>();
// Declare the children's size of the relation, and define that it is related to the parentInstances
@ManyToMany(mappedBy = "parentInstances", fetch = FetchType.LAZY)
private Set<InstanceEntity> childInstances = new HashSet<>();
//</editor-fold>
public void addParent(InstanceEntity parent) {
if (this.equals(parent))
throw new InvalidBindingOperationException("Cannot assign parent to himself");
parentInstances.add(parent);
}
public void addChild(InstanceEntity child) {
if (this.equals(child))
throw new InvalidBindingOperationException("Cannot assign child to himself");
childInstances.add(child);
}
@Override
public int hashCode() {
return Objects.hash(id, domain);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
InstanceEntity entity = (InstanceEntity) o;
return id == entity.id && domain.equals(entity.domain);
}
}
到目前为止,我尝试(可能天真地)为 parentInstance
编写 getter 并传递给它一个 Pagable
对象(因为它适用于 derived-queries
,所以值得shot ) 但显然它什么也没做。
我能想到的唯一解决方案是删除关系,然后手动创建它(使用另一个实体创建 table 并添加一个新的 PagingAndSortingRepository
来检索相关实例,然后转换他们在服务中 InstanceEntity
。
那么,如何为 parentInstances
和 childInstances
添加分页支持?
我在一些
所以我的解决方案是将以下功能添加到我的 PagingAndSortingRepository
界面:
Page<InstanceEntity> findDistinctByParentInstancesIn(@Param("parent_instances") Set<InstanceEntity> parentInstances, Pageable pageable);
然后调用它是:
InstanceEntity ie = new InstanceEntity();
ie.setDomain(parentDomain);
ie.setId(Long.parseLong(parentId));
instancesDao.findDistinctByParentInstancesIn(Collections.singleton(ie), PageRequest.of(page, size));
老实说,我不确定 how/why 它是否有效。 IntelliJ IDEA 在存储库界面 Expected parameter types: Collection<Set<InstanceEntity>>
.
所以如果有人有解释,我会很高兴听到。