草庐IT

java - 级联 ="all-delete-orphan"在与连接表的 Hibernate 单向多对多关联中有任何意义吗?

coder 2024-03-03 原文

我有两个对象形成父子关系,它们具有多对多关系。按照 Hibernate 引用手册中的建议,我使用连接表将其映射:

<class name="Conference" table="conferences">
    ...
    <set name="speakers" table="conference_speakers" cascade="all">
        <key column="conference_id"/>
        <many-to-many class="Speaker" column="speaker_id"/>
    </set>
</class>

<class name="Speaker" table="speakers">
    <id name="id" column="id">
        <generator class="native"/>
    </id>
    <property name="firstName"/>
    <property name="lastName"/>
</class>

我希望单个 Speaker 可以与许多不同的 Conferences 相关联,而且任何 Conference 不再引用的任何 Speaker 都将从 speakers 表中删除(作为没有任何 session 的 Speaker相关 session 在我的项目中没有太大意义)。

但是,我发现如果我使用 cascade="all-delete-orphan",那么如果与多个 session 关联的发言人被从其中一个 session 中删除,Hibernate 尝试删除 Speaker 实例本身。

下面是一个显示此行为的单元测试:

@Test
public void testRemoveSharedSpeaker() {

    int initialCount = countRowsInTable("speakers");

    Conference c1 = new Conference("c1");
    Conference c2 = new Conference("c2");

    Speaker s = new Speaker("John", "Doe");

    c1.getSpeakers().add(s);
    c2.getSpeakers().add(s);

    conferenceDao.saveOrUpdate(c1);
    conferenceDao.saveOrUpdate(c2);
    flushHibernate();

    assertEquals(initialCount + 1, countRowsInTable("speakers"));
    assertEquals(2, countRowsInTable("conference_speakers"));

    // the remove:
    c1 = conferenceDao.get(c1.getId());
    c1.getSpeakers().remove(s);

    flushHibernate();

    assertEquals("count should stay the same", initialCount + 1, countRowsInTable("speakers"));
    assertEquals(1, countRowsInTable("conference_speakers"));

    c1 = conferenceDao.get(c1.getId());
    c2 = conferenceDao.get(c2.getId());

    assertEquals(0, c1.getSpeakers().size());
    assertEquals(1, c2.getSpeakers().size());
}

处理从 c1.speakers 中删除 s 时会引发错误,因为 Hibernate 正在删除连接表中的行和 speakers 表格行:

DEBUG org.hibernate.SQL - delete from conference_speakers where conference_id=? and speaker_id=?
DEBUG org.hibernate.SQL - delete from speakers where id=?

如果我将 cascade="all-delete-orphan" 更改为 cascade="all",那么这个测试会按预期工作,尽管它会导致不希望的结果我将在 speakers 表中得到孤立行的行为。

这让我想知道 - Hibernate 是否甚至有可能知道何时从关系的子端删除孤立对象,但只有当该子对象未被任何其他父对象引用时(无论这些父对象是否被引用)在当前 Session 中)?也许我滥用了 cascade="all-delete-orphan"

如果我使用 JPA 注释而不是 XML 映射,我会得到完全相同的行为,例如:

@ManyToMany(cascade = CascadeType.ALL)
@JoinTable(name = "conference_speakers",
        joinColumns = @JoinColumn(name = "conference_id"),
        inverseJoinColumns = @JoinColumn(name = "speaker_id"))
@org.hibernate.annotations.Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
private Set<Speaker> speakers = new HashSet<Speaker>();

顺便说一句,这是与 Hibernate 3.6.7.Final 一起使用的。

最佳答案

DELETE_ORPHAN 级联模式未针对多对多关系定义 - 仅针对一对多(后者在 JPA 标准 @OneToMany 注释中具有“orphanRemoval=true|false”属性,因此您不必求助于专有的 Hibernate 注释)。

原因正如您所描述的那样——如果不对数据库运行查询,Hibernate 就无法确定多对多关系的“孤立”端是否真正孤立- 直观且(可能)具有严重的性能影响。

因此,您描述的 Hibernate 行为是正确的(好吧,“如文档所示”);尽管在一个完美的世界中,它会提醒您 DELETE_ORPHAN 在第二遍映射编译期间对多对多是非法的。

老实说,我想不出实现您想要做的事情的好方法。最简单(但特定于数据库)的方法可能是定义一个从 conference_speakers 中删除的触发器,该触发器将检查该发言人是否“真正”孤立并将其从 speakers 中删除如果是这样。与数据库无关的选项是在 DAO 或监听器中手动执行相同的操作。

更新:这是来自 Hibernate docs 的摘录(第 11.11 章,在 CascadeType.ALL 上的灰色注释之后),重点是我的:

A special cascade style, delete-orphan, applies only to one-to-many associations, and indicates that the delete() operation should be applied to any child object that is removed from the association.

再往下:

It does not usually make sense to enable cascade on a many-to-one or many-to-many association. In fact the @ManyToOne and @ManyToMany don't even offer a orphanRemoval attribute. Cascading is often useful for one-to-one and one-to-many associations.

关于java - 级联 ="all-delete-orphan"在与连接表的 Hibernate 单向多对多关联中有任何意义吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7613920/

有关java - 级联 ="all-delete-orphan"在与连接表的 Hibernate 单向多对多关联中有任何意义吗?的更多相关文章

  1. ruby-on-rails - rails : "missing partial" when calling 'render' in RSpec test - 2

    我正在尝试测试是否存在表单。我是Rails新手。我的new.html.erb_spec.rb文件的内容是:require'spec_helper'describe"messages/new.html.erb"doit"shouldrendertheform"dorender'/messages/new.html.erb'reponse.shouldhave_form_putting_to(@message)with_submit_buttonendendView本身,new.html.erb,有代码:当我运行rspec时,它失败了:1)messages/new.html.erbshou

  2. ruby-on-rails - 由于 "wkhtmltopdf",PDFKIT 显然无法正常工作 - 2

    我在从html页面生成PDF时遇到问题。我正在使用PDFkit。在安装它的过程中,我注意到我需要wkhtmltopdf。所以我也安装了它。我做了PDFkit的文档所说的一切......现在我在尝试加载PDF时遇到了这个错误。这里是错误:commandfailed:"/usr/local/bin/wkhtmltopdf""--margin-right""0.75in""--page-size""Letter""--margin-top""0.75in""--margin-bottom""0.75in""--encoding""UTF-8""--margin-left""0.75in""-

  3. ruby-on-rails - 如何验证 update_all 是否实际在 Rails 中更新 - 2

    给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru

  4. ruby - 检查 "command"的输出应该包含 NilClass 的意外崩溃 - 2

    为了将Cucumber用于命令行脚本,我按照提供的说明安装了arubagem。它在我的Gemfile中,我可以验证是否安装了正确的版本并且我已经包含了require'aruba/cucumber'在'features/env.rb'中为了确保它能正常工作,我写了以下场景:@announceScenario:Testingcucumber/arubaGivenablankslateThentheoutputfrom"ls-la"shouldcontain"drw"假设事情应该失败。它确实失败了,但失败的原因是错误的:@announceScenario:Testingcucumber/ar

  5. ruby - 续集在添加关联时访问many_to_many连接表 - 2

    我正在使用Sequel构建一个愿望list系统。我有一个wishlists和itemstable和一个items_wishlists连接表(该名称是续集选择的名称)。items_wishlists表还有一个用于facebookid的额外列(因此我可以存储opengraph操作),这是一个NOTNULL列。我还有Wishlist和Item具有续集many_to_many关联的模型已建立。Wishlist类也有:selectmany_to_many关联的选项设置为select:[:items.*,:items_wishlists__facebook_action_id].有没有一种方法可以

  6. java - 等价于 Java 中的 Ruby Hash - 2

    我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/

  7. ruby-on-rails - 迷你测试错误 : "NameError: uninitialized constant" - 2

    我遵循MichaelHartl的“RubyonRails教程:学习Web开发”,并创建了检查用户名和电子邮件长度有效性的测试(名称最多50个字符,电子邮件最多255个字符)。test/helpers/application_helper_test.rb的内容是:require'test_helper'classApplicationHelperTest在运行bundleexecraketest时,所有测试都通过了,但我看到以下消息在最后被标记为错误:ERROR["test_full_title_helper",ApplicationHelperTest,1.820016791]test

  8. ruby - 无法在 60 秒内获得稳定的 Firefox 连接 (127.0.0.1 :7055) - 2

    我使用的是Firefox版本36.0.1和Selenium-Webdrivergem版本2.45.0。我能够创建Firefox实例,但无法使用脚本继续进行进一步的操作无法在60秒内获得稳定的Firefox连接(127.0.0.1:7055)错误。有人能帮帮我吗? 最佳答案 我遇到了同样的问题。降级到firefoxv33后一切正常。您可以找到旧版本here 关于ruby-无法在60秒内获得稳定的Firefox连接(127.0.0.1:7055),我们在StackOverflow上找到一个类

  9. ruby-on-rails - 相关表上的范围为 "WHERE ... LIKE" - 2

    我正在尝试从Postgresql表(table1)中获取数据,该表由另一个相关表(property)的字段(table2)过滤。在纯SQL中,我会这样编写查询:SELECT*FROMtable1JOINtable2USING(table2_id)WHEREtable2.propertyLIKE'query%'这工作正常:scope:my_scope,->(query){includes(:table2).where("table2.property":query)}但我真正需要的是使用LIKE运算符进行过滤,而不是严格相等。然而,这是行不通的:scope:my_scope,->(que

  10. 使用 ACL 调用 upload_file 时出现 Ruby S3 "Access Denied"错误 - 2

    我正在尝试编写一个将文件上传到AWS并公开该文件的Ruby脚本。我做了以下事情:s3=Aws::S3::Resource.new(credentials:Aws::Credentials.new(KEY,SECRET),region:'us-west-2')obj=s3.bucket('stg-db').object('key')obj.upload_file(filename)这似乎工作正常,除了该文件不是公开可用的,而且我无法获得它的公共(public)URL。但是当我登录到S3时,我可以正常查看我的文件。为了使其公开可用,我将最后一行更改为obj.upload_file(file

随机推荐