当前位置: 首页 > 面试题库 >

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

金高飞
2023-03-14
问题内容

我正在迁移旧系统以使用Hibernate3。它当前会生成自己的标识符。为了在尝试将其移至更好一点之前,保持系统当前的功能,我将如何指定(使用注释)我自己的类,当发生插入时,该类将返回定制生成的标识符?

就像是:

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

其中Foo类具有生成所述标识符的一种方法。

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


问题答案:

我认为不存在使用纯JPA-2
API使用自定义注释生成自定义ID的现成支持。但是,如果要使用提供程序特定的API,则工作非常简单。样例

要独立于提供程序,请尝试以下任何技巧。

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};
    }
}

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

产品.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。如果持久性实体具有不同类型的ID .....

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()方法。但是,如果我们在no-
arg构造函数中将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将被更改!!!” 因此,最好在no-
arg构造函数中设置id。或为解决此问题,请放置不为null的检查…

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

如果将id生成放入无参数构造函数中,那么从数据库中加载实体时不会造成问题吗?因为hibernate将调用no-arg构造函数,导致现有ID重新生成

是的,您是对的,我错过了这一部分。:(实际上,我想告诉您:-在我的应用程序中,每个Entity对象都与Organization
Entity相关联;因此,我创建了一个具有两个构造函数的抽象超类,每个Entity(除Organization之外)都扩展了该类。

    protected PersistentEntityImpl() {
    }

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

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

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

第二个选项是使用@PrePersist批注。我把它放进去,该方法从未被击中,并给了我一个例外,指出我需要手动设置id。还有什么我应该做的吗?

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



 类似资料:
  • 如何将属性传递给gradle自定义任务?在ant中,它将如下所示: 在格拉德尔怎么做? 属性名称和版本是必需的,用户需要将它们传递给任务。

  • 我目前正在进行struts升级(从struts 1.x迁移到2.x) 我的项目有一个自定义标记处理程序类,用于格式化应用程序中的数字 TLD文件 FormatNumberTag类 JSP 这里,AccountBean是bean,floatingRate是属性 1)在标签处理程序类上面,(org.apache.struts.util.请求Utils)请求Utils.lookup 相应的方法是什么 2

  • 此代码在没有警告的情况下编译。标准对此是怎么说的? 声明为。因此,不应优化对此变量的读取。 但是,bar不是限定的。是否允许编译器优化对此的写入?.即。编译器将对进行读取访问,并允许丢弃该值,而不将其分配给(在L.7处)。 如果这是标准有话要说的特殊情况,可否请您加入该条款,并对标准的律师谈话进行解读?

  • 我想对我的Vue使用Firebase身份验证。js应用程序考虑以下限制: 我无法使用任何受支持的提供商(Facebook、Google等) 我不能使用电子邮件-该应用程序是为孩子们设计的,因此,我想使用他们在注册时选择的唯一昵称,而不是电子邮件,该昵称必须使用本地rtl语言(非英语) 我想使用firebase云函数作为唯一的服务器端代码 期望的结果是:a)使用昵称、密码注册 如何使用firebas

  • Amazon EMR是否允许将系统属性传递给自定义jar,例如hadoop jar-Dkey=value-myjob。jar?(

  • 我正在学习本教程,其中要求使用分配给Azure存储帐户的Azure托管标识。https://docs.microsoft.com/en-us/azure/storage/common/customer-managed-keys-overview#about-客户管理的密钥 在本教程中,请参见步骤1。是: Azure Key Vault管理员向与存储帐户关联的托管标识授予加密密钥权限 但是,我找不到