我对实体进行了版本控制,作为其主键的一部分。版本控制是通过上次修改的时间戳完成的:
@Entity
@Table(name = "USERS")
@IdClass(CompositeKey.class)
public class User {
@Column(nullable = false)
private String name;
@Id
@Column(name = "ID", nullable = false)
private UUID id;
@Id
@Column(name = "LAST_MODIFIED", nullable = false)
private LocalDateTime lastModified;
// Constructors, Getters, Setters, ...
}
/**
* This class is needed for using the composite key.
*/
public class CompositeKey {
private UUID id;
private LocalDateTime lastModified;
}
UUID
会自动转换为数据库的String
并返回模型。 LocalDateTime
也是如此。它会自动转换为Timestamp
并返回。
我的应用程序的一个关键要求是:数据可能永远不会更新或被删除,因此任何更新都会产生一个年轻lastModified
的新条目。此要求已满足上面的代码和工作正常,直到这一点。
现在出现问题部分:我希望另一个对象引用用户。由于版本控制,这将包括lastModified
字段,因为它是主键的一部分。这会产生一个问题,因为引用可能会很快过时。
一种方法可能取决于id
的{{1}}。但是,如果我试试这个,JPA告诉我,我想访问一个不是User
的字段:
Entity
解决我的困境的正确方法是什么?
修改
我得到了JimmyB的建议,我尝试过但也失败了。我在这里添加了失败的代码:
@Entity
@Table(name = "USER_DETAILS")
public class UserDetail {
@Id
@Column(nullable = false)
private UUID id;
@OneToOne(optional = false)
@JoinColumn(name = "USER_ID", referencedColumnName = "ID")
private UUID userId;
@Column(nullable = false)
private boolean married;
// Constructors, Getter, Setter, ...
}
答案 0 :(得分:0)
这里有一个合乎逻辑的1:1关系,由于版本控制,它成为技术上的1:n关系。
您基本上有三种选择:
@ManyToOne
从用户到"其他对象&#34}的关系并确保在创建新的User
记录时始终处理它。@OneToMany
关系并使用@JoinColumn
强制它使用一组特定的列进行连接。这样做的问题是JPA总是期望连接列上的唯一引用,以便读取 UserDetail
加上引用的User
记录应该有效,而写 UserDetail
不级联到User
以避免不受欢迎/未记录的影响。UUID
存储在"其他对象"并在需要时自行解决参考。你问题中添加的代码是错误的:
@JoinColumn(name = "USER_ID", referencedColumnName = "ID")
private UUID userId;
更正确,虽然没有你想要的结果,但
@JoinColumn(name = "USER_ID", referencedColumnName = "ID")
private User user;
这不会起作用,因为正如我上面所说,每UserDetail
个用户记录可能不止一个,因此您需要@OneToMany
这里的Collection<User>
关系,由User
表示。
另一个&#39;清洁&#39;解决方案是引入一个具有1:1基数w.r.t的人工实体。到您可以引用的逻辑@Entity
public class UserId {
@Id
private UUID id;
@OneToMany(mappedBy="userId")
private List<User> users;
@OneToOne(mappedBy="userId")
private UserDetail detail;
}
@Entity
public class User {
@Id
private Long _id;
@ManyToOne
private UserId userId;
}
@Entity
public class UserDetail {
@OneToOne
private UserId userId;
}
,例如
{{1}}
通过这种方式,您可以轻松地从用户导航到详细信息并返回。
答案 1 :(得分:0)
我找到了一个解决方案,但这并不令人满意,但有效。我创建了一个UUID
字段userId
,它没有绑定到Entity
,并确保它只在构造函数中设置。
@Entity
@Table(name = "USER_DETAILS")
public class UserDetail {
@Id
@Column(nullable = false)
private UUID id;
@Column(nullable = false)
// no setter for this field
private UUID userId;
@Column(nullable = false)
private boolean married;
public UserDetail(User user, boolean isMarried) {
this.id = UUID.randomUUID();
this.userId = user.getId();
this.married = isMarried;
}
// Constructors, Getters, Setters, ...
}
我不喜欢这样一个事实,即我不能依赖数据库来同步userId
,但只要我坚持不设置策略,就应该可以很好地工作。
答案 2 :(得分:0)
您似乎需要的内容似乎位于历史记录表的行上,以跟踪更改。请参阅https://wiki.eclipse.org/EclipseLink/Examples/JPA/History,了解EclipseLink如何在使用普通/传统JPA映射和使用时为您处理此问题。