我在创建正确的JPQL查询时遇到问题,无法通过以下表格加入:
在GROUPS和USERS之间有一个传统的@ManyToMany映射表, DOCUMENTS_GROUPS 是导致问题的原因。正如您在以下实体中所看到的,我希望将 DOCUMENTS 和 GROUPS 之间的关系映射为包含 access_mode 的Map(其工作原理)除了查询之外就好了:
@Entity
@Table(name = "DOCUMENTS")
@NamedQueries({
@NamedQuery(
name = "Documents.findAccessibleByUser",
query = "SELECT d FROM Document d INNER JOIN d.groups g INNER JOIN KEY(g).members m WHERE m.id = :userId"
)
})
public class Document {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int id;
@ElementCollection
@CollectionTable(name = "DOCUMENTS_GROUPS", joinColumns = {@JoinColumn(name = "document_id")})
@MapKeyJoinColumn(name = "group_id")
@Column(name = "access_mode")
@Enumerated(EnumType.STRING)
private Map<Group, AccessMode> groups = new HashMap<>();
/* ... */
}
随着群体变得正常:
@Entity
@Table(name = "GROUPS")
public class Group {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int id;
@Column(length = 255)
private String name;
@ManyToMany
@JoinTable(name = "USERS_GROUPS", //
joinColumns = {@JoinColumn(name = "group_id")}, //
inverseJoinColumns = {@JoinColumn(name = "user_id")} //
)
private Set<User> members = new HashSet<>();
/* ... */
}
我的问题是:我如何修改JPQL查询中的第二个JOIN?
SELECT d FROM Document d
INNER JOIN d.groups g
INNER JOIN KEY(g).members m
WHERE m.id = :userId
语法错误(KEY
之后的意外INNER JOIN
。
当然,我已经尝试过简单INNER JOIN g.members m
,但由于我们正在处理Map<Group, AccessMode>
,因此cannot dereference scalar collection element: members
失败。
答案 0 :(得分:0)
我也遇到了一个简单的键值Map<String, String>
遇到的相同问题:
@Entity
Item.java
@ElementCollection
@MapKeyColumn(name = "name")
@Column(name = "value")
@CollectionTable(indexes = @Index(columnList = "value"))
private Map<String, String> attributes = new HashMap<>();
可以加入属性:
Query query = em.createQuery("SELECT i FROM Item i INNER JOIN i.attributes attr");
但不查询字段:
Query query = em.createQuery("SELECT i FROM Item i INNER JOIN i.attributes attr WHERE attr.value = 'something'");
我调试了Hibernate内部结构,发现别名attr
已经解析为值(e.attributes.value
),因此您在这里只能做的事情是
Query query = em.createQuery("SELECT i FROM Item i INNER JOIN i.attributes attr WHERE attr = 'something'");
但是我没有找到任何指出这一点的文档或JPQL示例。在我的情况下,这种行为是没有用的,因为我想同时拥有键和值的条件。这就是为什么我使用键映射和组合主键迁移到外部实体集合的原因。它的方法比较复杂,但可以正常工作。
防止单个主键的组合键实体
@Embeddable
public class ItemAttributeName implements Serializable {
private String name;
@ManyToOne
@JoinColumn(nullable = false)
private Item item;
// Empty default constructor is important
public ItemAttributeName() {
}
public ItemAttributeName(Item item, String name) {
this.item = article;
this.name = name;
}
}
真实属性实体
@Entity
public class ItemAttribute {
@EmbeddedId
private ItemAttributeName id;
private String value;
// Empty default constructor is important
public ItemAttribute() {
}
public ItemAttribute(Item item, String name) {
this.id = new ItemAttributeName (item, name);
}
public String getValue() {
return value;
}
}
@Entity
Item.java
@OneToMany(mappedBy = "id.item",cascade = CascadeType.PERSIST)
@MapKeyColumn(name = "name")
public Map<String, ItemAttribute> attributes = new HashMap<>();
创建实体
Item item = new Item ();
ItemAttribute fooAttribute = new ItemAttribute(item, "foo");
fooAttribute.setValue("356");
item.attributes.put("foo", fooAttribute);
查询实体
Query query = em.createQuery("SELECT i FROM Item i JOIN i.attributes attr WHERE attr.id.name = 'foo' AND attr.value='bar'");
List<Item> resultList = query.getResultList();
System.out.println(resultList.get(0).attributes.get("foo").getValue());
打印出: bar