将自定义标识符分配给@id属性
我正在迁移旧系统以使用Hibernate 3.它当前会生成自己的标识符。为了保持系统当前的功能,然后尝试将其移到更好的位置,我将如何指定(使用注释)我自己的类,以便在插入时返回自定义生成的标识符?将自定义标识符分配给@id属性
是这样的:
@Id
@CustomIdGenerator(Foo.class) // obviously this is not a real annotation
public String getId() { ... }
凡Foo
类具有生成所述标识符的一种方法。
目前我只是手动调用setId(String id)
方法,但希望有一个更好的方法来处理这种情况。
我不认为这是用于使用定制标注使用纯JPA的2 API定制标识出的现成的支持。但是如果你想使用提供商特定的API,那么这项工作非常简单。 Sample Example
要独立提供者尝试以下任何技巧....
IdGeneratorHolder
public abstract class IdGeneratorHolder {
/* PersistentEntity is a marker interface */
public static IdGenerator getIdGenerator(Class<? extends PersistentEntity> entityType) {
/* sample impelementation */
if(Product.class.isAssignableFrom(entityType)) {
return new ProductIdGenerator();
}
return null;
}
}
一般IdGenerator接口
public interface IdGenerator {
String generate();
}
具体IdGenerator - 产品ID生成
public class ProductIdGenerator implements IdGenerator {
public String generate() {
/* some complicated logic goes here */
return ${generatedId};
}
}
现在将生成的ID或者设置为无参数构造函数或,使用@PrePersist方法。
Product.java
public class Product implements PersistentEntity {
private String id;
public Product() {
id = IdGeneratorHolder.getIdGenerator(getClass()).generate();
}
@PrePersist
public void generateId() {
id = IdGeneratorHolder.getIdGenerator(getClass()).generate();
}
}
在上面的例子中所有的ID具有相同的类型,即java.lang.String
的。如果持久实体有不同类型的IDS .....
IdGenerator.java
public interface IdGenerator {
CustomId generate();
}
CustomId.java
public class CustomId {
private Object id;
public CustomId(Object id) {
this.id = id;
}
public String toString() {
return id.toString();
}
public Long toLong() {
return Long.valueOf(id.toString());
}
}
Item.java
@PrePersist
public void generateId() {
id = IdGeneratorHolder.getIdGenerator(getClass()).generate().toLong();
}
您还可以使用自定义的注释......
CustomIdGenerator.java
public @interface CustomIdGenerator {
IdStrategy strategy();
}
IdStrategy.java
enum IdStrategy {
uuid, humanReadable,
}
IdGeneratorHolder.java
public abstract class IdGeneratorHolder {
public static IdGenerator getIdGenerator(Class<? extends PersistentEntity> entityType) {
try { // again sample implementation
Method method = entityType.getMethod("idMethod");
CustomIdGenerator gen = method.getAnnotation(CustomIdGenerator.class);
IdStrategy strategy = gen.strategy();
return new ProductIdGenerator(strategy);
}
还有一件事......如果我们在@PrePersist方法中设置了id,则equals()方法不能依赖id字段(即,代理键),我们必须使用业务/自然键来实现equals()方法。但是,如果我们在无参数构造函数中将id字段设置为某个唯一值(uuid或应用程序中唯一的“app-uid”),它可以帮助我们实现equals()方法。
public boolean equals(Object obj) {
if(obj instanceof Product) {
Product that = (Product) obj;
return this.id ==that.id;
}
return false;
}
如果我们或他人通话(有意或错误)的@PrePersist注解的方法1倍以上,“唯一的ID将被改变!”所以在no-arg构造函数中设置id是可取的。或者为了解决这个问题,把一个非空检查...
@PrePersist
public void generateId() {
if(id != null)
id = IdGeneratorHolder.getIdGenerator(getClass()).generate();
}
}
UPDATE
如果我们把ID生成的 无参数的构造函数,那不是 从数据库加载实体 时产生问题?因为Hibernate 将调用无参数的构造 导致现有的IDS是 重新生成
是的,你说得对,我错过了一部分。 :(其实,我想告诉你的是: - 在我的应用程序中每个实体对象与组织实体相关联的,所以我创建了一个抽象的超类有两个构造函数,每一个实体(组织除外)扩展该类
protected PersistentEntityImpl() {
}
protected PersistentEntityImpl(Organization organization) {
String entityId = UUIDGenerator.generate();
String organizationId = organization.getEntityId();
identifier = new EntityIdentifier(entityId, organizationId);
}
的无参数的构造是JPA的供应商,我们从来没有调用无参数的构造函数,但其他组织根据构造函数。正如你所看到的,ID是在基础的组织构造函数分配的。(我真的错过了这一点同时写出答案,对不起)
看看你是否可以在你的应用中实现这个或者类似的策略
第二个选项是使用 @PrePersist批注。我把在 和方法不会被击中,并给了我 的异常,说明我需要 手动设置的ID。是否有 我应该做的其他事情?
理想情况下,在保持实体对象之前,JPA提供者应该调用@PrePersist方法(在类中声明的方法以及在超类中声明的所有其他方法)。不能告诉你什么是错的,除非你显示一些代码和控制台。
您可以。
一是落实org.hibernate.id.IdentifierGenerator
然后,你必须将它在映射xml文件映射。我不能找到一种方法用注解做到这一点:
<!--
<identifier-generator.../> allows customized short-naming
of IdentifierGenerator implementations.
-->
<!ELEMENT identifier-generator EMPTY>
<!ATTLIST identifier-generator name CDATA #REQUIRED>
<!ATTLIST identifier-generator class CDATA #REQUIRED>
最后,使用@GeneratedValue(generator="identifier-name")
注意,这是休眠特定的(不是JPA)
更新:我花了看看Hibernate的来源,看起来在一个地方,在解决短名称失败后,休眠尝试呼叫Class.forName(..)
。那里的参数叫做strategy
。因此,这里是你尝试什么:
- 尝试在
generator
属性 - 尝试在
@GenericGenerator
strategy
属性设置类FQN为字符串(有一些任意名称)
让我知道(如果有的话)的工作
我看过一样,如果可能的话,想避免xml文件。但是如果我找不到替代品,我想我会诉诸于此。谢谢! – digiarnie 2010-11-24 01:47:09
@digiarnie看到更新 – Bozho 2010-11-24 07:27:00