java 覆盖 Hibernate 注释

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3229833/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 00:54:28  来源:igfitidea点击:

Override Hibernate Annotations

javahibernatejpa

提问by rynmrtn

I am developing a Java Application that uses Hibernate and is connected to an Oracle instance. Another client is looking to use the same application, but requires it run on MS SQL Server. I would like to avoid making changes to the existing annotations and instead create a package of xml files that we can drop in depending on the environment.

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

One way to do this is using JPA XML configuration to override the existing class annotations. However, JPA does not support generic generators, which is a requirement due to the structure of our legacy database. The other way that I am looking into is to use Hibernate XML configs to remap entire classes and have access to the generatorxml tag. This solution has some issues though:

一种方法是使用 JPA XML 配置来覆盖现有的类注释。但是,JPA 不支持通用生成器,这是由于我们遗留数据库的结构所必需的。我正在研究的另一种方法是使用 Hibernate XML 配置来重新映射整个类并可以访问generatorxml 标记。但是这个解决方案有一些问题:

  • Hibernate does not allow you to selectively override entity members
  • Hibernate does not allow you to re-map the same class (e.g. org.hibernate.AnnotationException: Use of the same entity name twice)
  • Hibernate 不允许您有选择地覆盖实体成员
  • Hibernate 不允许您重新映射同一个类(例如org.hibernate.AnnotationException: Use of the same entity name twice

Does anyone have any experience with overriding annotations using Hibernate XML Configuration files or is JPA the only way to go?

有没有人有使用 Hibernate XML 配置文件覆盖注释的经验,或者 JPA 是唯一的方法吗?

Update with an Example

更新示例

In Oracle, Sequences are used to generate unique IDs when inserting new records into the database. An id would then be annotated in the following manner:

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

However, MS SQL Server does not have the concept of Sequences (Ideological differences). Therefore, you could use a table generator to simulate sequences.

但是,MS SQL Server 没有 Sequences(意识形态差异)的概念。因此,您可以使用表生成器来模拟序列。

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

Two different configurations for two different types of databases. Keep in mind that this is a legacy database and that we aren't going to rewrite our application to support SQL Server identities, the native id generator for SQL Server (which would also require a different annotation).

两种不同类型数据库的两种不同配置。请记住,这是一个遗留数据库,我们不会重写我们的应用程序以支持 SQL Server 身份,即 SQL Server 的本机 id 生成器(这也需要不同的注释)。

To alleviate this, I have looked into using Hibernate's @GenericGeneratorand point it to a class of my own creation that models org.hibernate.id.SequenceGenerator(or something similar) and also customize the structure of the table by extending org.hibernate.id.TableStructure.

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

Back to my original question - is any of this possible with an XML override?

回到我最初的问题 - XML 覆盖是否可以实现这些?

How I Solved this Problem

我是如何解决这个问题的

So, in the end, I found that JPA and Hibernate did not provide the out-of-box functionality that I was looking for. Instead, I created a custom generator that checked the database dialect and set the TableStructure appropriately. As I explored all options, I ended up using Hibernate's @GenericGeneratorannotation. This is an example of the Id generation annotation:

所以,最后,我发现 JPA 和 Hibernate 没有提供我正在寻找的开箱即用的功能。相反,我创建了一个自定义生成器,用于检查数据库方言并适当地设置 TableStructure。在探索所有选项时,我最终使用了 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;
}

This solution necessitates that each Hibernate entity be modified with the new Id generator.

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

回答by Bozho

I think that if you don't use AnnotationConfigurationwhen configuring your SessionFactory, the annotations will be omitted.

我认为如果您AnnotationConfiguration在配置您的SessionFactory.时不使用,则注释将被省略。

So, use Configuration.

所以,使用Configuration.

回答by james

For your generator problem (for which the solution would normally be "use the native generator" but doesn't work for you due to working with a legacy db), you could probably extend the SQLServerDialect and override the getNativeIdentifierGeneratorClass to return a (possibly custom) generator that does what you need for your legacy db.

对于您的生成器问题(解决方案通常是“使用本机生成器”,但由于使用旧数据库而对您不起作用),您可以扩展 SQLServerDialect 并覆盖 getNativeIdentifierGeneratorClass 以返回(可能是自定义的) ) 生成器可以满足您的旧数据库所需。

回答by mikesalera

I have come across the need to mix-n-match legacy with new schemas/databases before in a Grails (GORM) application, which of course is running Hibernate 3 underneath.

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

Would not say "you're doing it wrong" - but I would keep the JPA @Annotations to the very basics like @Entity and @Column and leave it to the Hibernate dialect, which is also specified in the XML configuration file.

不会说“你做错了”——但我会将 JPA @Annotations 保留为非常基础的东西,比如 @Entity 和 @Column 并将它留给 Hibernate方言,这也在 XML 配置文件中指定。

You might experiment with subclassing the Oracle10gDialect with one that assigns a sequence generator to all tables, versus a Sybase one which does not.

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

Please see this poston how to implement this.

请参阅这篇文章了解如何实现这一点。

UPDATE: What james and I are suggesting (almost in the same minute) is to setup multiple persistence-unit sections of your persistence.xml file.

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

This allows one to use @Entity and @Id without supplying details in the class. The details come in the hibernate.dialectproperty. I suggested subclassing Oracle10gDialect (and james the SQLServerDialect) - those would do the choosing as to the table naming, id generator strategy, etc.

这允许使用 @Entity 和 @Id 而无需在类中提供详细信息。详情请见hibernate.dialect物业。我建议子类化 Oracle10gDialect(和 James SQLServerDialect)——那些可以选择表命名、id 生成器策略等。

See --> https://forum.hibernate.org/viewtopic.php?f=1&t=993012

见--> https://forum.hibernate.org/viewtopic.php?f=1&t=993012

回答by divestoclimb

If you rewrite the annotations in HBM XML files, you could maintain two sets of such XML and pick which ones to use via Hibernate's mapping directives. I've done this in Hibernate Core, but not in a J2EE/JPA environment so I don't know if there are any gotchas in that respect.

如果您在 HBM XML 文件中重写注释,您可以维护两组这样的 XML,并通过 Hibernate 的映射指令选择使用哪些。我已在 Hibernate Core 中完成此操作,但未在 J2EE/JPA 环境中完成此操作,因此我不知道在这方面是否存在任何问题。

The biggest downside is it likely will be a lot of work to remove all your annotations and rebuild them in XML.

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

回答by AniJaglan

In my case:

就我而言:

Rack and Slot are entities having custom ID Generators. I am using unidirectional one-to-one mapping. Dimension table will hold the data with a Autogenerated Custom ID as foreign key for multiple tables (Rack and Slot for example here). And my schemalooks like this : Rack ------> Dimension <-----------Slot where Dimension will hold the data for Rack and Slot table with Generated ID.

机架和插槽是具有自定义 ID 生成器的实体。我正在使用单向一对一映射。维度表将使用自动生成的自定义 ID 保存数据作为多个表的外键(例如此处的机架和插槽)。我的架构如下所示:Rack ------> Dimension <-----------Slot 其中 Dimension 将保存带有生成 ID 的 Rack 和 Slot 表的数据。

Here the concern is that when i am saving the data like this:-

这里的问题是,当我像这样保存数据时:-

Rack rack = new Rack(params);
Dimension dim = new Dimension(params);
rack.setDimension(dim);
session.save(rack);

Data is being saved successfully with same Autogenerated ID in Rack and Dimension Tables.

在机架和维度表中使用相同的自动生成的 ID 成功保存数据。

But when I am saving the data for Slot table :

但是当我为 Slot 表保存数据时:

Slot Slot = new Slot(params);
Dimension dim = new Dimension(params);
slot.setDimension(dim);
session.save(slot);

it is showing error message as:-

它显示错误消息为:-

attempted to assign id from null one-to-one property: rack

Can I pass the dynamic property name as "slot" when saving the data for Slot and Dimension and "rack" when saving the data for Rack and Dimension.

我可以在保存 Slot 和 Dimension 的数据时将动态属性名称作为“slot”传递,在保存 Rack 和 Dimension 的数据时传递“rack”。



@GenericGenerator(name = "foreign", strategy = "foreign", parameters = {
    @Parameter(name = "property", value = "slot"),
    @Parameter(name = "property", value = "rack")})

Rack.java

Rack.java

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

Slot.java

插槽.java

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

Dimension.java

维度.java

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
}

回答by james

I would say that if your annotations are database specific, you're doing it wrong.

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