A
とB
の2つのエンティティがあります。それらの間には多対多の関係があり、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);
};
}
}