使用 JPA 保留整数列表?
我们有一个 pojo 需要有一个整数列表。例如,我创建了一个 Message
pojo,并希望关联一个 groupIds
列表(这些 id 需要在 UI 中查询并显示)。因此,理想情况下,我们希望能够做这样的事情:
Message msg = em.find(Message.class, 101);
List<Integer> groupIds = msg.getGroupIds();
我的印象是,这只需要一个带有 JPA 的 pojo,但根据 在这里讨论,我需要创建第二个pojo,因为JPA以对象的形式工作的原始类型。
从该讨论中,我尝试了以下示例代码,但收到错误 openjpa-1.2.3-SNAPSHOT-r422266:907835 fatal user error: org.apache.openjpa.util.MetaDataException: The type of field "声明的持久性策略“ManyToOne”不支持 pojo.Group.messageId”。请选择不同的策略。
DDL:
CREATE TABLE "APP"."MESSAGE" ( "MESSAGE_ID" INTEGER NOT NULL GENERATED ALWAYS AS IDENTITY (START WITH 1, INCREMENT BY 1), "AUTHOR" CHAR(20) NOT NULL ); ALTER TABLE "APP"."MESSAGE" ADD CONSTRAINT "MESSAGE_PK" PRIMARY KEY ("MESSAGE_ID"); CREATE TABLE "APP"."GROUP_ASSOC" ( "GROUP_ID" INTEGER NOT NULL, "MESSAGE_ID" INTEGER NOT NULL ); ALTER TABLE "APP"."GROUP_ASSOC" ADD CONSTRAINT "GROUP_ASSOC_PK" PRIMARY KEY ("MESSAGE_ID", "GROUP_ID"); ALTER TABLE "APP"."GROUP_ASSOC" ADD CONSTRAINT "GROUP_ASSOC_FK" FOREIGN KEY ("MESSAGE_ID") REFERENCES "APP"."MESSAGE" ("MESSAGE_ID");
POJOs:
@Entity
@Table(name = "MESSAGE")
public class Message {
@Id
@Column(name = "MESSAGE_ID")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long messageId;
@OneToMany
private List<Group> groups = new ArrayList<Group>();
@Column(name = "AUTHOR")
private String author;
// getters/setters ommitted
}
@Entity
@IdClass(pojo.Group.GroupKey.class)
@Table(name = "GROUP_ASSOC")
public class Group {
@Id
@Column(name = "GROUP_ID")
private Long groupId;
@Id
@Column(name = "MESSAGE_ID")
@ManyToOne
private Long messageId;
public static class GroupKey {
public Long groupId;
public Long messageId;
public boolean equals(Object obj) {
if(obj == this) return true;
if(!(obj instanceof Group)) return false;
Group g = (Group) obj;
return g.getGroupId() == groupId && g.getMessageId() == messageId;
}
public int hashCode() {
return ((groupId == null) ? 0 : groupId.hashCode())
^ ((messageId == null) ? 0 : messageId.hashCode());
}
}
// getters/setters ommitted
}
测试代码:
EntityManager em = Persistence.createEntityManagerFactory("JPATest").createEntityManager();
em.getTransaction().begin();
Message msg = new Message();
msg.setAuthor("Paul");
em.persist(msg);
List<Group> groups = new ArrayList<Group>();
Group g1 = new Group();
g1.setMessageId(msg.getMessageId());
Group g2 = new Group();
g2.setMessageId(msg.getMessageId());
msg.setGroups(groups);
em.getTransaction().commit();
这一切看起来都很荒谬 -- 3 个类(如果包含 GroupKey 复合身份类)来建模整数列表 -- 难道没有更优雅的吗解决方案?
We have a pojo that needs to have a list of integers. As an example, I've created a Message
pojo and would like to associate a list of groupIds
(these ids need to be queried and displayed in the UI). So ideally, we would like to be able to do something like this:
Message msg = em.find(Message.class, 101);
List<Integer> groupIds = msg.getGroupIds();
I was under the impression that this would require only one pojo with JPA, but according to the discussion here, I need to create a second pojo because JPA works in terms of objects instead of primitive types.
From that discussion I've tried the following example code, but I get the error openjpa-1.2.3-SNAPSHOT-r422266:907835 fatal user error: org.apache.openjpa.util.MetaDataException: The type of field "pojo.Group.messageId" isn't supported by declared persistence strategy "ManyToOne". Please choose a different strategy.
DDL:
CREATE TABLE "APP"."MESSAGE" ( "MESSAGE_ID" INTEGER NOT NULL GENERATED ALWAYS AS IDENTITY (START WITH 1, INCREMENT BY 1), "AUTHOR" CHAR(20) NOT NULL ); ALTER TABLE "APP"."MESSAGE" ADD CONSTRAINT "MESSAGE_PK" PRIMARY KEY ("MESSAGE_ID"); CREATE TABLE "APP"."GROUP_ASSOC" ( "GROUP_ID" INTEGER NOT NULL, "MESSAGE_ID" INTEGER NOT NULL ); ALTER TABLE "APP"."GROUP_ASSOC" ADD CONSTRAINT "GROUP_ASSOC_PK" PRIMARY KEY ("MESSAGE_ID", "GROUP_ID"); ALTER TABLE "APP"."GROUP_ASSOC" ADD CONSTRAINT "GROUP_ASSOC_FK" FOREIGN KEY ("MESSAGE_ID") REFERENCES "APP"."MESSAGE" ("MESSAGE_ID");
POJOs:
@Entity
@Table(name = "MESSAGE")
public class Message {
@Id
@Column(name = "MESSAGE_ID")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long messageId;
@OneToMany
private List<Group> groups = new ArrayList<Group>();
@Column(name = "AUTHOR")
private String author;
// getters/setters ommitted
}
@Entity
@IdClass(pojo.Group.GroupKey.class)
@Table(name = "GROUP_ASSOC")
public class Group {
@Id
@Column(name = "GROUP_ID")
private Long groupId;
@Id
@Column(name = "MESSAGE_ID")
@ManyToOne
private Long messageId;
public static class GroupKey {
public Long groupId;
public Long messageId;
public boolean equals(Object obj) {
if(obj == this) return true;
if(!(obj instanceof Group)) return false;
Group g = (Group) obj;
return g.getGroupId() == groupId && g.getMessageId() == messageId;
}
public int hashCode() {
return ((groupId == null) ? 0 : groupId.hashCode())
^ ((messageId == null) ? 0 : messageId.hashCode());
}
}
// getters/setters ommitted
}
Test Code:
EntityManager em = Persistence.createEntityManagerFactory("JPATest").createEntityManager();
em.getTransaction().begin();
Message msg = new Message();
msg.setAuthor("Paul");
em.persist(msg);
List<Group> groups = new ArrayList<Group>();
Group g1 = new Group();
g1.setMessageId(msg.getMessageId());
Group g2 = new Group();
g2.setMessageId(msg.getMessageId());
msg.setGroups(groups);
em.getTransaction().commit();
This all seems ridiculous -- 3 classes (if you include the GroupKey composite identity class) to model a list of integers -- isn't there a more elegant solution?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
这是一个老话题,但自 OpenJPA2 以来情况发生了变化,现在您可以直接保留原始类型或 String 对象。使用 ElementCollection 注释来使用简单的一对多链接,无需中间对象或链接表。这就是我们大多数人创建 SQL 模式的方式。
This is an old topic but things have changed since OpenJPA2, now you can directly persist primitive types or String object. Use ElementCollection annotation to use simple one-to-many linking, no need to intermediate object or link tables. This is how most of us probably create SQL schemas.
我真的认为您所拥有的实际上是两个实体之间的多对多关联(我们称它们为
消息
和组
)。表示这一点的 DDL 为:
和带注释的类:
不过,我不确定您是否需要双向关联。但是如果你想使用JPA,你肯定需要开始考虑对象(在你的例子中,你仍然在设置id,你应该设置实体)。或者也许 JPA 不是您所需要的。
我不确定“优雅”是否合适,但 JPA 2.0 定义了
ElementCollection
映射(正如我在之前的回答中所说):但这是 JPA 2.0 中的情况。在 JPA 1.0 中,如果您的提供商确实提供了此类扩展,则您必须使用提供商特定的等效项。看来 OpenJPA 确实使用
@PersistentCollection
。I really think that what you have is in fact a many-to-many association between two Entities (let's call them
Message
andGroup
).The DDL to represent this would be:
And the annotated classes:
I'm not sure you need a bi-directional association though. But you definitely need to start to think object if you want to use JPA (in you're example, you're still setting ids, you should set Entities). Or maybe JPA is not what you need.
I'm not sure "elegant" is appropriate but JPA 2.0 defines an
ElementCollection
mapping (as I said in my previous answer):But that's in JPA 2.0. In JPA 1.0, you would have to use a provider specific equivalent, if your provider does offer such an extension. It appears that OpenJPA does with
@PersistentCollection
.根据您的架构,组和消息之间存在多对一关系。这意味着一条消息可以属于多个组,但每个组可以有一条消息。
这些实体看起来像这样。
您的应用程序中不需要 IDClass(如果您的 ID 包含多列,则只需要一个)。
要获取给定消息的 groupId,您可以编写如下查询
,或者只是迭代 Message.getGroups() :
Based on your schema you have a ManyToOne relationship between Group and Message. Which means that a single Message can belong to multiple groups, but each group can have a single message.
The entities would look something like this.
There's no need for an IDClass in your app (you only need one if your ID is contains multiple columns).
To get the groupIds for a given message you could write a query like this one
Or just iterate over Message.getGroups() :