このエンティティがあり、同じプロパティ セットを持つエンティティを検索したいと考えています。
@Entity
public class PropertyResource {
@ElementCollection
@MapKeyColumn(name = "property_key")
@Column(name = "property_value")
@CollectionTable(name = "resource_properties")
private Map<String, String> properties = Maps.newHashMap();
...
}
これは、基準ビルダーを使用した私の実装です。
public List<PropertyResource> findDuplicateProperties(PropertyResource resource) {
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<PropertyResource> query = builder.createQuery(PropertyResource.class);
Root<PropertyResource> resourceRoot = query.from(PropertyResource.class);
List<Predicate> clauses = Lists.newArrayList();
for (Entry<String, String> entry : resource.getProperties().entrySet()) {
MapJoin<PropertyResource, String, String> properties = resourceRoot.joinMap("properties", JoinType.INNER);
clauses.add(builder.and(builder.equal(properties.key(), entry.getKey()), builder.equal(properties.value(), entry.getValue())));
}
if (!resource.isNew()) {
clauses.add(builder.notEqual(resourceRoot.get("id"), resource.getID()));
}
clauses.add(builder.equal(resourceRoot.get("type"), resource.getType()));
return em.createQuery(query.where(clauses.toArray(new Predicate[clauses.size()]))).getResultList();
}
プロパティごとに追加の結合を行っています。同じタイプのプロパティとリソースが同じプロパティ キーを持つことはあまりありません。これは、これを生成する h2 でうまく機能します。
select ...
from resource_table propertyre0_
inner join resource_properties properties1_ on propertyre0_.entid=properties1_.PropertyResource_entid
inner join resource_properties properties2_ on propertyre0_.entid=properties2_.PropertyResource_entid
where properties1_.property_key=? and properties1_.property_value=?
and properties2_.property_key=? and properties2_.property_value=?
and propertyre0_.entid<>4 and propertyre0_.resource_type=?
ただし、Oracleの場合は次のようになります。
select ...
from resource_table propertyre0_
where propertyre0_.entid<>230 and propertyre0_.resource_type=?
私のクエリに何か問題がありますか?
OBS: ほとんど忘れていました。Hibernate のバージョンは 4.1.9.Final です。