Spring 集合的数据规范包含操作
Spring Data Specification for set contains operation
我有两个实体,A
和 B
。它们之间存在多对多关系,其中 A
持有 B
的列表。 如何编写规范来检索包含具有特定名称的 B
的所有 A
实体? 示例:
@Service
public class YourService {
@Resource
private ARepository repository;
// I know how to do this type of queries with specifications
public List<A> getByB(B b) {
return repository.findAll(Specifications.containsB(b));
}
//Question: how to write Specification for this type of query?
public List<A> getByNameOfB(String name) {
return repository.findAll(Specifications.containsBWithName(name));
}
}
实体:
@Entity
public class B {
@Id
@SequenceGenerator(sequenceName = "B_SEQ", name = "BSeq", allocationSize = 1)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "BSeq")
private Long id;
@Column(unique = true, updatable = false)
private String name;
}
@Entity
public class A {
@Id
@SequenceGenerator(sequenceName = "A_SEQ", name = "ASeq", allocationSize = 1)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "ASeq")
private Long id;
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(name = "A_B",
joinColumns = {@JoinColumn(name = "A_ID", nullable = false, updatable = false)},
inverseJoinColumns = {@JoinColumn(name = "B_ID", nullable = false, updatable = false)})
@Fetch(value = FetchMode.SUBSELECT)
private List<B> bList;
}
元模型:
@Generated(value = "org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor")
@StaticMetamodel(A.class)
public class A_ {
public static volatile ListAttribute<A, B> bList;
}
@Generated(value = "org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor")
@StaticMetamodel(B.class)
public class B_ {
public static volatile SingularAttribute<B, String> name;
}
检索:
public interface ARepository extends JpaRepository<A, Long>, JpaSpecificationExecutor<A> {
}
public class Specifications {
public static Specification<A> containsB(B b) {
return (root, query, cb) -> {
Expression<List<B>> bList = root.get(A_.bList);
return cb.isMember(b, bList);
};
}
// HERE IS A QUESTION:
public static Specification<A> containsBWithName(String name) {
return (root, query, cb) -> {
ListJoin<List<B>> bList = root.join(A_.bList);
Expression<String> exp = bList.get(B_.name)
//TODO how to check that name is one of the retrieved names?
//PROBLEM, method below expects Expression<List<String>> instead of Expression<String>
cb.isMember(name, exp);
};
}
}
尝试下一步:
public static Specification<A> containsBWithName(String name) {
return (root, query, cb) -> {
root.join("bList", JoinType.INNER);
return cb.equal(root.get("bList").get("name"), name);
};
}
希望它能奏效。
Spring数据版本1.11.4
我花了一些时间才弄清楚为什么接受的答案对我不起作用。
我不得不这样做:
public static Specification<A> containsBWithName(String name) {
return (root, query, cb) -> {
Join<Object, Object> bListJoin = root.join("bList", JoinType.INNER);
return cb.equal(bListJoin.get("name"), name);
};
}
Spring 数据 1.11.9
我有两个实体,A
和 B
。它们之间存在多对多关系,其中 A
持有 B
的列表。 如何编写规范来检索包含具有特定名称的 B
的所有 A
实体? 示例:
@Service
public class YourService {
@Resource
private ARepository repository;
// I know how to do this type of queries with specifications
public List<A> getByB(B b) {
return repository.findAll(Specifications.containsB(b));
}
//Question: how to write Specification for this type of query?
public List<A> getByNameOfB(String name) {
return repository.findAll(Specifications.containsBWithName(name));
}
}
实体:
@Entity
public class B {
@Id
@SequenceGenerator(sequenceName = "B_SEQ", name = "BSeq", allocationSize = 1)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "BSeq")
private Long id;
@Column(unique = true, updatable = false)
private String name;
}
@Entity
public class A {
@Id
@SequenceGenerator(sequenceName = "A_SEQ", name = "ASeq", allocationSize = 1)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "ASeq")
private Long id;
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(name = "A_B",
joinColumns = {@JoinColumn(name = "A_ID", nullable = false, updatable = false)},
inverseJoinColumns = {@JoinColumn(name = "B_ID", nullable = false, updatable = false)})
@Fetch(value = FetchMode.SUBSELECT)
private List<B> bList;
}
元模型:
@Generated(value = "org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor")
@StaticMetamodel(A.class)
public class A_ {
public static volatile ListAttribute<A, B> bList;
}
@Generated(value = "org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor")
@StaticMetamodel(B.class)
public class B_ {
public static volatile SingularAttribute<B, String> name;
}
检索:
public interface ARepository extends JpaRepository<A, Long>, JpaSpecificationExecutor<A> {
}
public class Specifications {
public static Specification<A> containsB(B b) {
return (root, query, cb) -> {
Expression<List<B>> bList = root.get(A_.bList);
return cb.isMember(b, bList);
};
}
// HERE IS A QUESTION:
public static Specification<A> containsBWithName(String name) {
return (root, query, cb) -> {
ListJoin<List<B>> bList = root.join(A_.bList);
Expression<String> exp = bList.get(B_.name)
//TODO how to check that name is one of the retrieved names?
//PROBLEM, method below expects Expression<List<String>> instead of Expression<String>
cb.isMember(name, exp);
};
}
}
尝试下一步:
public static Specification<A> containsBWithName(String name) {
return (root, query, cb) -> {
root.join("bList", JoinType.INNER);
return cb.equal(root.get("bList").get("name"), name);
};
}
希望它能奏效。
Spring数据版本1.11.4
我花了一些时间才弄清楚为什么接受的答案对我不起作用。 我不得不这样做:
public static Specification<A> containsBWithName(String name) {
return (root, query, cb) -> {
Join<Object, Object> bListJoin = root.join("bList", JoinType.INNER);
return cb.equal(bListJoin.get("name"), name);
};
}
Spring 数据 1.11.9