草庐IT

java - 为什么 Hibernate 有时会加载错误子类的实例?

coder 2024-03-08 原文

我们有一个我们无法解释的关于 hibernate 的奇怪问题。

我们有什么:

  1. 一个抽象类和它的两个子类。让我们称他们为 A、SubA1、SubA2
  2. 我们有另一个抽象类和一些子类。让 B、SubB1、SubB2 调用。
  3. SubB1 和 A 之间存在多对一关系。
  4. A 类和 B 类的 hibernate 映射如下所示:

    <hibernate-mapping>
    
      <class name="A" table="A" lazy="false">
    
        <id name="id" column="ID" type="java.lang.Integer">
          <generator class="org.hibernate.id.enhanced.TableGenerator">
            <param name="segment_value">a</param>
          </generator>
        </id>
    
        <version name="olVersion" column="VERSION" type="integer" unsaved-value="negative" />
    
        <joined-subclass name="SubA1" table="SUB_A1" lazy="false">
          <key column="ID_A" foreign-key="FK_SUB_A1_A"/>
          <property name="p1" column="p1" length="255" unique="true"/>
          <property name="p2" column="p2" length="255" not-null="true" />
        </joined-subclass>
    
        <joined-subclass name="SubA2" table="SUB_A2" lazy="false">
          <key column="ID_A" foreign-key="FK_SUB_A2_A"/>
          <property name="p3" column="p3" length="255" not-null="true" unique="true" />
          <property name="p4" column="p4" length="4000" />
        </joined-subclass>
    
      </class>
    
    </hibernate-mapping>
    

<hibernate-mapping>

  <class name="B" table="B" lazy="false">

    <cache usage="read-write"/>

    <id name="id" column="ID" type="java.lang.Integer">
      <generator class="org.hibernate.id.enhanced.TableGenerator">
        <param name="segment_value">b</param>
      </generator>
    </id>

    <version name="olVersion" column="VERSION" type="integer" unsaved-value="negative" />

    <joined-subclass name="SubB1" table="SUB_B1" lazy="false">
      <key column="ID_B" foreign-key="FK_SUB_B1_B"/>
      <many-to-one name="subA" column="ID_A" not-null="false" update="false" foreign-key="FK_SUB_B1" lazy="false" class="A"/>
    </joined-subclass>

  </class>

</hibernate-mapping>

现在的问题是:有时 hibernate 通过加载 SubB1 的项目将 SubA2 的项目加载为 SubA1 的实例,但并非所有项目都会投错,只有少数项目,而且每次都不是相同的项目。

也许有人可以解释,出了什么问题或我们的 hibernate 映射有什么问题。

提前谢谢你。

附言。 此问题发生在:

  • JDK 1.7.71
  • 甲骨文 12g
  • hibernate 3.6.10

我没有尝试其他配置。

不幸的是,我没有示例应用程序,但我也无法提供真实应用程序的源代码。

最佳答案

我认为您的 hibernate 映射是正确的。所以如果你有错误,我相信它会发生在施法时间。我多次遇到这个问题,我总是使用访问者模式解决它。

访问者模式的另一个优点是你不需要强制lazy=false,因为它完美地解决了代理对象的真实类型。

如何解决你的问题

我建议您创建一个 Visitor 类,它为每个 A 具体子类实现两个 visit 方法:

  • void visit(SubA1 object)
  • 无效访问(SubA2 对象)

这两种方法的实现都是当A实例是SubA1SubA2具体类时你要执行的代码。我放了 void return,但显然你可以改变它。

另一方面,A类必须添加抽象访问方法public abstract void visit(Visitor visitor);。再一次,我将 void 返回,但您必须将其调整为 visit 方法的返回类型。

SubA1SubA2 必须按如下方式实现此方法:

public void accept(Visitor visitor) {
    visitor.visit(this);
}

这样,当您运行此代码 objectA.accept(visitor) 时,Java 必须在运行时解析 objectA 的真实类型,无需转换,也不会出现错误。它确实有效,我在 Hibernate 3.x 和 4.x 中使用它多年。

访问者模式文档

这里有一篇非常好的文章 Proxy Visitor Pattern您可以在其中找到如何在使用代理和非代理对象时将访问者模式应用于 hibernate 。

希望对您有所帮助!

关于java - 为什么 Hibernate 有时会加载错误子类的实例?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32529903/

有关java - 为什么 Hibernate 有时会加载错误子类的实例?的更多相关文章

  1. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  2. ruby-on-rails - Rails - 子类化模型的设计模式是什么? - 2

    我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co

  3. ruby-on-rails - Rails 常用字符串(用于通知和错误信息等) - 2

    大约一年前,我决定确保每个包含非唯一文本的Flash通知都将从模块中的方法中获取文本。我这样做的最初原因是为了避免一遍又一遍地输入相同的字符串。如果我想更改措辞,我可以在一个地方轻松完成,而且一遍又一遍地重复同一件事而出现拼写错误的可能性也会降低。我最终得到的是这样的:moduleMessagesdefformat_error_messages(errors)errors.map{|attribute,message|"Error:#{attribute.to_s.titleize}#{message}."}enddeferror_message_could_not_find(obje

  4. ruby - 什么是填充的 Base64 编码字符串以及如何在 ruby​​ 中生成它们? - 2

    我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%

  5. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  6. ruby - 为什么 4.1%2 使用 Ruby 返回 0.0999999999999996?但是 4.2%2==0.2 - 2

    为什么4.1%2返回0.0999999999999996?但是4.2%2==0.2。 最佳答案 参见此处:WhatEveryProgrammerShouldKnowAboutFloating-PointArithmetic实数是无限的。计算机使用的位数有限(今天是32位、64位)。因此计算机进行的浮点运算不能代表所有的实数。0.1是这些数字之一。请注意,这不是与Ruby相关的问题,而是与所有编程语言相关的问题,因为它来自计算机表示实数的方式。 关于ruby-为什么4.1%2使用Ruby返

  7. ruby - 如何在续集中重新加载表模式? - 2

    鉴于我有以下迁移:Sequel.migrationdoupdoalter_table:usersdoadd_column:is_admin,:default=>falseend#SequelrunsaDESCRIBEtablestatement,whenthemodelisloaded.#Atthispoint,itdoesnotknowthatusershaveais_adminflag.#Soitfails.@user=User.find(:email=>"admin@fancy-startup.example")@user.is_admin=true@user.save!ende

  8. ruby-on-rails - 如何使用 instance_variable_set 正确设置实例变量? - 2

    我正在查看instance_variable_set的文档并看到给出的示例代码是这样做的:obj.instance_variable_set(:@instnc_var,"valuefortheinstancevariable")然后允许您在类的任何实例方法中以@instnc_var的形式访问该变量。我想知道为什么在@instnc_var之前需要一个冒号:。冒号有什么作用? 最佳答案 我的第一直觉是告诉你不要使用instance_variable_set除非你真的知道你用它做什么。它本质上是一种元编程工具或绕过实例变量可见性的黑客攻击

  9. ruby 正则表达式 - 如何替换字符串中匹配项的第 n 个实例 - 2

    在我的应用程序中,我需要能够找到所有数字子字符串,然后扫描每个子字符串,找到第一个匹配范围(例如5到15之间)的子字符串,并将该实例替换为另一个字符串“X”。我的测试字符串s="1foo100bar10gee1"我的初始模式是1个或多个数字的任何字符串,例如,re=Regexp.new(/\d+/)matches=s.scan(re)给出["1","100","10","1"]如果我想用“X”替换第N个匹配项,并且只替换第N个匹配项,我该怎么做?例如,如果我想替换第三个匹配项“10”(匹配项[2]),我不能只说s[matches[2]]="X"因为它做了两次替换“1fooX0barXg

  10. ruby - ruby 中的 TOPLEVEL_BINDING 是什么? - 2

    它不等于主线程的binding,这个toplevel作用域是什么?此作用域与主线程中的binding有何不同?>ruby-e'putsTOPLEVEL_BINDING===binding'false 最佳答案 事实是,TOPLEVEL_BINDING始终引用Binding的预定义全局实例,而Kernel#binding创建的新实例>Binding每次封装当前执行上下文。在顶层,它们都包含相同的绑定(bind),但它们不是同一个对象,您无法使用==或===测试它们的绑定(bind)相等性。putsTOPLEVEL_BINDINGput

随机推荐