gpt4 book ai didi

java - 将自定义标识符分配给 @id 属性

转载 作者:塔克拉玛干 更新时间:2023-11-03 03:47:31 25 4
gpt4 key购买 nike

我正在将遗留系统迁移到使用 Hibernate 3。它目前生成自己的标识符。为了在我尝试将其转移到更好的东西之前保持系统当前所做的事情,我将如何指定(使用注释)我自己的类,该类将在发生插入时返回自定义生成的标识符?

类似于:

@Id
@CustomIdGenerator(Foo.class) // obviously this is not a real annotation
public String getId() { ... }

Foo 类有一个生成标识符的方法。

目前我只是手动调用 setId(String id) 方法,但希望有更好的方法来处理这种情况。

最佳答案

我认为对于使用纯 JPA-2 API 使用自定义注释生成自定义 ID 没有开箱即用的支持。但是如果你想使用提供者特定的 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();
}

Specific IdGenerator - 产品 ID 生成器

public class ProductIdGenerator implements IdGenerator {
public String generate() {
/* some complicated logic goes here */
return ${generatedId};
}
}

现在在无参数构造函数中在@PrePersist方法中设置生成的id。

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 注解方法,“唯一标识将被更改!!!”因此,最好在无参数构造函数中设置 id。或者为了解决这个问题,进行非空检查...

  @PrePersist
public void generateId() {
if(id != null)
id = IdGeneratorHolder.getIdGenerator(getClass()).generate();
}
}

更新

If we put the id generation in a no-arg constructor, wouldn't that cause a problem when loading entities from the database? because hibernate will call the no-arg constructor causing existing ids to be re-generated

是的,你是对的,我错过了那部分。 :( 实际上,我想告诉你:- 在我的应用程序中,每个实体对象都与一个组织实体相关联;所以我创建了一个具有两个构造函数的抽象父类(super class),每个实体(组织除外)都扩展了这个类。

    protected PersistentEntityImpl() {
}

protected PersistentEntityImpl(Organization organization) {
String entityId = UUIDGenerator.generate();
String organizationId = organization.getEntityId();
identifier = new EntityIdentifier(entityId, organizationId);
}

无参数构造函数用于 JPA 提供者,我们从不调用无参数构造函数,而是调用其他基于组织的构造函数。如你看到的。 id 在基于组织的构造函数中分配。 (我在写答案时真的错过了这一点,对此感到抱歉)。

看看您是否可以在您的应用程序中实现此策略或类似策略。

The second option was using the @PrePersist annotation. I put that in and the method never got hit and gave me an exception stating that I needed to set the id manually. Is there something else I should be doing?

理想情况下,JPA 提供者应该在持久化实体对象之前调用@PrePersist 方法(在类中声明的方法以及在父类(super class)中声明的所有其他方法)。无法告诉您哪里出了问题,除非您显示一些代码和控制台。

关于java - 将自定义标识符分配给 @id 属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4262600/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com