Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/333.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 覆盖Hibernate注释_Java_Hibernate_Jpa - Fatal编程技术网

Java 覆盖Hibernate注释

Java 覆盖Hibernate注释,java,hibernate,jpa,Java,Hibernate,Jpa,我正在开发一个使用Hibernate并连接到Oracle实例的Java应用程序。另一个客户端希望使用相同的应用程序,但要求它在MS SQL Server上运行。我希望避免对现有注释进行更改,而是创建一个xml文件包,根据环境的不同,我们可以访问这些文件包 一种方法是使用JPA XML配置覆盖现有的类注释。然而,JPA不支持通用生成器,这是由于我们遗留数据库的结构所要求的。我正在研究的另一种方法是使用HibernateXMLConfigs重新映射整个类,并访问generatorXML标记。不过,此

我正在开发一个使用Hibernate并连接到Oracle实例的Java应用程序。另一个客户端希望使用相同的应用程序,但要求它在MS SQL Server上运行。我希望避免对现有注释进行更改,而是创建一个xml文件包,根据环境的不同,我们可以访问这些文件包

一种方法是使用JPA XML配置覆盖现有的类注释。然而,JPA不支持通用生成器,这是由于我们遗留数据库的结构所要求的。我正在研究的另一种方法是使用HibernateXMLConfigs重新映射整个类,并访问
generator
XML标记。不过,此解决方案存在一些问题:

  • Hibernate不允许您有选择地覆盖实体成员
  • Hibernate不允许您重新映射同一类(例如,
    org.Hibernate.AnnotationException:两次使用同一实体名称
有没有人有使用HibernateXML配置文件覆盖注释的经验,或者JPA是唯一的方法

更新一个例子 在Oracle中,将新记录插入数据库时,序列用于生成唯一ID。然后,将以以下方式对id进行注释:

@Id
@GeneratedValue(generator="EXAMPLE_ID_GEN", strategy=GenerationType.SEQUENCE)
@SequenceGenerator(name="EXAMPLE_ID_GEN", sequenceName="SEQ_EXAMPLE_ID")
@Column(name = "EXAMPLE_ID")
public String getExampleId() {
    return this.exampleId;
}
但是,MS SQL Server没有序列的概念(意识形态差异)。因此,可以使用表生成器来模拟序列

@Id
@GeneratedValue(generator="EXAMPLE_ID_GEN", strategy=GenerationType.TABLE)
@TableGenerator(name="EXAMPLE_ID_GEN", tableName="SEQUENCE", valueColumnName="VALUE", pkColumnName="SEQUENCE", pkColumnValue="EXAMPLE_ID")
public String getExampleId() {
    return this.exampleId;
}
针对两种不同类型的数据库的两种不同配置。请记住,这是一个遗留数据库,我们不会重写应用程序以支持SQL Server标识,即SQL Server的本机id生成器(这也需要不同的注释)

为了缓解这种情况,我研究了使用Hibernate的
@GenericGenerator
,并将其指向我自己创建的一个类,该类对org.Hibernate.id.SequenceGenerator(或类似的东西)建模,还通过扩展
org.Hibernate.id.TableStructure
来定制表的结构

回到我最初的问题——使用XML覆盖是否有可能做到这一点

我是如何解决这个问题的 所以,最后,我发现JPA和Hibernate并没有提供我想要的现成功能。相反,我创建了一个自定义生成器,用于检查数据库方言并适当地设置表结构。在探索所有选项时,我最终使用了Hibernate的
@GenericGenerator
注释。这是Id生成注释的一个示例:

@Id
@GeneratedValue(generator="EXAMPLE_ID_GEN")
@GenericGenerator(name = "EXAMPLE_ID_GEN", strategy="com.my.package.CustomIdGenerator", parameters = {
        @Parameter(name = "parameter_name", value="parameter_value")
})
public String getExampleId() {
    return this.exampleId;
}

此解决方案需要使用新的Id生成器修改每个Hibernate实体。

我认为,如果您的注释是特定于数据库的,那么您就错了。

我认为,如果您在配置
会话工厂时不使用
注释配置
,注释将被忽略


因此,使用
配置

解决您的生成器问题(解决方案通常是“使用本机生成器”,但由于使用遗留数据库而不适用于您),您可能会扩展SQLServer方言并覆盖getNativeIdentifierGeneratorClass以返回一个(可能是自定义的)生成器,它可以满足您的遗留数据库的需要。

我以前在Grails(GORM)应用程序中遇到过将遗留数据库与新模式/数据库混合匹配的需要,该应用程序当然在下面运行Hibernate 3

我不会说“你做错了”——但我会将JPA@注释保留在@Entity和@Column之类的基础上,并将其留给Hibernate方言,这也是在XML配置文件中指定的

您可以尝试将Oracle10gDialogue子类化为一个为所有表分配序列生成器的子类,而Sybase子类则没有

关于如何实现这一点,请参见本文

更新:
james和我建议(几乎在同一分钟内)在persistence.xml文件中设置多个持久性单元部分

这允许使用@Entity和@Id,而无需在类中提供详细信息。详细信息在
hibernate.dialogue
属性中。我建议将Oracle10gDialogue(以及SQLServerDialogue的james)子类化——这些子类可以选择表命名、id生成器策略等


请参阅-->

如果在HBM XML文件中重写注释,则可以维护两组这样的XML,并通过Hibernate的映射指令选择要使用的XML。我在Hibernate Core中做过,但在J2EE/JPA环境中没有,所以我不知道在这方面是否存在任何缺陷

最大的缺点是删除所有注释并用XML重建它们可能需要大量工作。

在我的例子中:

机架和插槽是具有自定义ID生成器的实体。我使用单向一对一映射。维度表将保存具有自动生成的自定义ID的数据,作为多个表的外键(例如此处的机架和插槽)。
我的想法是这样的:在现实世界中,Rack------->Dimension使用“遗留”和“现有应用程序”这两个术语,说“你做错了”是没有帮助的。Oracle和SQL Server在数据库设计上存在理念上的差异,为了弥合两者之间的差距,需要在配置(即注释)上有所不同@rynmrtn:我想他想指出的是,JPA应该已经独立于数据库了。。。数据存储已经可以通过persistence.xml进行配置。他的回答特别引用了特定于数据库的注释,而不是persistence.xml。这仍然是一个没有答案的答案。我支持ORM的这个答案。也就是说,我将尝试在另一个答案中给出一些有针对性的建议。如果您指出需要处理注释中的哪些差异,可能会有所帮助
Rack rack = new Rack(params);
Dimension dim = new Dimension(params);
rack.setDimension(dim);
session.save(rack);
Slot Slot = new Slot(params);
Dimension dim = new Dimension(params);
slot.setDimension(dim);
session.save(slot);
attempted to assign id from null one-to-one property: rack
@GenericGenerator(name = "foreign", strategy = "foreign", parameters = {
    @Parameter(name = "property", value = "slot"),
    @Parameter(name = "property", value = "rack")})
@Entity
@Table(name="tablename")
@GenericGenerator(name = "customseq", strategy = "CustomIdGenerator")
public class Rack {
  @Id
  @GeneratedValue(generator = "customseq")
  @Column(name = "uni_id")
  private String id;
  @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
  @PrimaryKeyJoinColumn
  private Dimension dimension;
  // Getters and Setters
}
@Entity
@Table(name="tablename")
@GenericGenerator(name = "customseq", strategy = "CustomIdGenerator")
public class Rack {
    @Id
    @GeneratedValue(generator = "customseq")
    @Column(name = "uni_id")
    private String id;
    @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @PrimaryKeyJoinColumn
    private Dimension dimension;
    // Getters and Setters
}
public class Dimension implements Serializable{
  @Id
  @Column(name = "systemid")
  @GeneratedValue(generator = "foreign")
  @GenericGenerator(name = "foreign", strategy = "foreign", parameters = {
    @Parameter(name = "property", value = "slot"),
    @Parameter(name = "property", value = "rack")})
  private String systemid;

  @OneToOne(mappedBy = "dimension", fetch = FetchType.LAZY)
  @PrimaryKeyJoinColumn
  private Rack rack;
  @OneToOne(mappedBy = "dimension", fetch = FetchType.LAZY)
  @PrimaryKeyJoinColumn
  private Slot slot;
  // Getters and Setters
}