我正在尝试构建一个复杂的查询。我的实体看起来如下:
@Entity
public class Configuration{
@Id
@Column(name="CONF_ID")
protected Long configurationId;
@ManyToMany
@MapKey(name="componentType")
@JoinTable(name="CONF_COMP",
joinColumns={@JoinColumn(name="CONF_ID", referencedColumnName="CONF_ID")},
inverseJoinColumns={@JoinColumn(name="COMP_ID", referencedColumnName="componentId")})
protected Map<String, Component> components;
}
并且
@Entity
public class Component {
@Id
protected long componentId;
@ElementCollection
protected Map<String, String> properties;
@ManyToMany(mappedBy="components")
private List<Configuration> configurations;
@Column(name="COMP_TYPE")
protected String componentType;
}
我的问题在于正确查询properties
字段。我似乎无法创建一个查询来获取所有配置,其中组件A具有属性Prop1 = 1而组件B具有属性Prop2 = 2。
我尝试了以下但没有成功。
Root<Configuration> conf = cq.from(Configuration.class);
MapJoin<Configuration, String, Component> compJoin = conf.join(Configuration_.components, JoinType.LEFT);
MapJoin<Component, String, String> propJoin = compJoin.join(Component_.properties, JoinType.LEFT);
Predicate p1 = cb.and(
cb.equal(mapJoin.key(), "A"),
cb.equal(propJoin.key(), "Prop1"), cb.equal(propJoin.value(), "1"));
Predicate p2 = cb.and(
cb.equal(mapJoin.key(), "B"),
cb.equal(propJoin.key(), "Prop2"), cb.equal(propJoin.value(), "2"));
Predicate[] pArray = new Predicate[]{p1, p2};
cq.where(pArray);
cq.select(conf).distinct(true);
编辑:记录器输出的查询如下所示:
SELECT DISTINCT t2.CONF_ID, t2.DTYPE, t2.TOTALPRICE, t2.NAME
FROM CONFIGURATION t2
LEFT OUTER JOIN (CONF_COMP t3 JOIN COMPONENT t1 ON (t1.COMPONENTID = t3.COMP_ID)) ON (t3.CONF_ID = t2.CONF_ID) LEFT OUTER JOIN Component_PROPERTIES t0 ON (t0.Component_COMPONENTID = t1.COMPONENTID)
WHERE (((((t1.COMP_TYPE = ?) AND (t0.PROPERTIES_KEY = ?)) AND t0.PROPERTIES LIKE ?) AND (((t1.COMP_TYPE = ?) AND (t0.PROPERTIES_KEY = ?)) AND t0.PROPERTIES LIKE ?)) AND (t2.DTYPE = ?))
bind => [7 parameters bound]
我猜它正在尝试找到一个配置,其中所有条件都适用于SAME组件?如果我只对一个Component应用限制,它会起作用,但是当应用2个或更多时,我得到一个空的结果列表,尽管DB中的条目满足条件。
更新
按照Pimgd的建议,我最终得到了一个如下所示的查询:
SELECT DISTINCT t1.CONF_ID, t1.DTYPE, t1.TOTALPRICE, t1.NAME
FROM CONFIGURATION t1 LEFT OUTER JOIN (CONF_COMP t2 JOIN COMPONENT t0 ON (t0.COMPONENTID = t2.COMP_ID)) ON (t2.CONF_ID = t1.CONF_ID)
WHERE (((
t0.COMPONENTID IN (SELECT t3.COMPONENTID
FROM COMPONENT t3 LEFT OUTER JOIN Component_PROPERTIES t4 ON (t4.Component_COMPONENTID = t3.COMPONENTID)
WHERE ((t4.PROPERTIES_KEY = Brand) AND (t4.PROPERTIES = Intel))))
AND
t0.COMPONENTID IN (SELECT t6.COMPONENTID
FROM COMPONENT t6 LEFT OUTER JOIN Component_PROPERTIES t7 ON (t7.Component_COMPONENTID = t6.COMPONENTID)
WHERE ((t7.PROPERTIES_KEY = Capacity) AND t7.PROPERTIES LIKE 4GB%))))
一个标准有效,两个没有结果。
非常感谢任何帮助!
答案 0 :(得分:1)
我要说的
mapJoin.key()
应为compJoin.key()
。
除此之外,我没有看到任何错误。
如果我提供的解决方案不起作用,这里有一些奖励问题:
我发现有趣的一点:
WHERE (((((t1.COMP_TYPE = ?) AND (t0.PROPERTIES_KEY = ?)) AND t0.PROPERTIES LIKE ?) AND (((t1.COMP_TYPE = ?) AND (t0.PROPERTIES_KEY = ?)) AND t0.PROPERTIES LIKE ?)) AND (t2.DTYPE = ?))
如果,我把这一点拿出来......只是为了澄清。 ((t1.COMP_TYPE = ?) AND (t0.PROPERTIES_KEY = ?))
WHERE (((SNIP AND t0.PROPERTIES LIKE ?) AND (SNIP AND t0.PROPERTIES LIKE ?)) AND (t2.DTYPE = ?))
所以是的......
现在你将如何修复你的查询?
可悲的是,我不是专家。
但我所知道的是,如果您使用WHERE t2.CONF_ID IN (Subselect for criteria A) AND t2.CONF_ID IN (Subselect for criteria B)
进行查询。
我的建议是查找子选项并滥用它们。 JPA 2.0, Criteria API, Subqueries, In Expressions解释了它,似乎足够相关。