【问题标题】:Spring hibernate ManyToMany with extra fields带有额外字段的 Spring 休眠 ManyToMany
【发布时间】:2016-02-18 17:56:12
【问题描述】:

我正在开发一个演示项目,该项目具有连接多对多的驱动程序和许可证。司机可以拥有更多的驾照,一张驾照可以连接更多的驾驭者。这不是驾驶执照。我所说的许可证与他们可以或不能运输的货物有关。这就是它应该的方式。 最近,我有一个请求要在此连接中添加两个额外的字段。 Driver 和 License 通过表 Drivers_License 连接 ManyToMany。额外提交给 Drivers_License,即 expireDate 和 stateIssued。

这是我的数据库现在的样子。

Driver                          Driver_License                   License
-----------                     -------------------             --------------------
driverID                         driverID                         licenseID
driverName                       licenseID                        licenseName
driverNumber                     expirationDate    
driverDateOfBirth                stateIssued

问题是我需要中断多对多连接并创建两个单对多连接。我还需要由 driverID 和 licenseID 组成复合密钥。

这就是我所说的例子。 Hibernate Many-to-Many Association with Extra Columns in Join Table Example

您能否告诉我是否有一些完整的示例如何使用 spring 和 hibernate 来完成此操作,或者您是否知道一些可以通过以经典方式使用 ManyToMany 来处理此问题的示例?

【问题讨论】:

  • 您对表有控制权还是从实体生成架构?
  • 架构是在实体上生成的。
  • 酷。那为什么不把新的两个新字段放在 License Entity 中呢?
  • 所以你的意思是我可以使用 ManyToMany 并将这些字段放在 License 中而不是 DriverLicense 中?会尝试的。但是数据库有什么变化吗?
  • 好吧,我没有看到任何特别需要多对多的东西。 OneToMany 会做到这一点。但是让我们明确一点,我问这些表是由您的应用程序生成的还是预先存在的?或者,也许您有一个创建脚本。无论如何,新字段将进入许可证表(和实体)。

标签: java spring hibernate


【解决方案1】:

只要您自己创建架构,就不需要将字段添加到join table。只需将它们添加到您的许可证Entity。这将是您似乎正在尝试做的事情的近似值。

@Entity
public class Driver {    
    @Id @GeneratedValue private Integer id;
    @OneToMany private List<License> licenses;
    ... Driver Name, Number, & DateOfBirth ...
}

@Entity
public class License {    
    @Id @GeneratedValue private Integer id;
    private String licenseName;
    // add your fields here.
    @Temporal(TemporalType.DATE)
    private Date expirationDate;
    private String issueState;
}

同样,您不想弄乱join table,它们通常由持久性提供程序自动创建。

Driver 表中的licenses 列表将引用一个join table,该join table 将为一个驱动程序持有许多许可证,因此是OneToMany 关系。

编辑:如果您有一个特定的许可证并且想要找出它属于哪个驱动程序,比如说因为您已经通过它的名称查找它,那么您应该添加一个对驱动程序的引用:

@ManyToOne
private Driver driver;

这将是一个ManyToOne,因为您将拥有许多涉及一个驱动程序的许可证。此关系将使用与Driver 中的licenses 列表使用的相同Join Table。这也会创建一个循环引用,Driver 指的是LicenseLicense 指的是Driver。您必须首先创建Licenses,保存它们,创建Driver,添加许可证,保存它,然后将mergeDriver 放入License

    for(License license: licenses) {
        em.persist(license);
    }
    Driver driver = new Driver();
    driver.getLicenses().add(licenses);
    em.persist(driver);
    // merge circular dependency
    for(License license: licenses) {
        license.setDriver(driver);
        em.merge(license);
    }

好建议:您应该打开SQL 输出并稍微试用一下该应用程序,以了解它可以做什么以及它是如何做到的。看到一切在行动将帮助您更好地了解它是如何工作的。我通常用创建、打印、删除等按钮制作一个简单的网页,然后观察调试输出。

【讨论】:

  • 好的。这看起来很棒。您在第二个实体中写了 Driver 而不是 License。
  • 那么在驱动表中有licenseID是否可以,可以序列化的license id数组?这是以防万一司机有更多的许可证。这些是他驾驶的货物的许可证。
  • 我只是不知道如何组织数据库表。我认为到期日期和签发的状态应该属于驱动程序。
  • 好吧,我想我终于有了完整的画面。我将拥有您在此处发布的实体。在数据库中,我将有表 Driver 和 License,其中包含 id、driverID、licenseName、expirationDate、stateIssued。我将再使用一张表来保存 9 种类型的许可证,这些许可证将在视图中提供,例如可供选择的表单元素。
  • 查看我的更新。大多数情况下,请考虑使用您目前拥有的东西,看看它是如何工作的。
【解决方案2】:

好的。就像我在这里承诺的那样,这是我的解决方案。 Nicolas 帮助我解决了我的 Entity 组织中的一些问题,等等。

对于我的特殊问题,我选择了这个:http://www.codejava.net/frameworks/hibernate/hibernate-many-to-many-association-with-extra-columns-in-join-table-example

这解决了使用休眠的问题。我还使用 DTO 重新包装 bean。这个例子有一个错误,那就是他们在创建复合 ID 时没有使用 LAZY。这就是这个例子有无限循环问题的原因。

这是我解决这个问题的代码。

驱动实体

@OneToMany(fetch = FetchType.LAZY, mappedBy = "id.driver", cascade = CascadeType.ALL)

 private List<DriverLicense> driverLicense = new ArrayList<DriverLicense>();

 public List<DriverLicense> getDriverLicense() {
   return driverLicense;

 public void setDriverLicense(List<DriverLicense> driverLicense) {
   this.driverLicense = driverLicense;
 }

DriverLicenseID(我的复合密钥)

@Embeddable
public class DriverLicenseID implements Serializable { 

    private static final long serialVersionUID = 1L;

    @ManyToOne(fetch = FetchType.LAZY, cascade=CascadeType.ALL) 
    @JoinColumn(name="driverID")
    private Driver driver;

    public Driver getDriver() {
        return driver;
    }

    public void setDriver(Driver driver) {
        this.driver = driver;
    }

    @ManyToOne(fetch = FetchType.LAZY, cascade=CascadeType.ALL)
    private License license;

    public License getLicense() {
        return license;
    }

    public void setLicense(License license) {
        this.license = license;
    } 
}

许可实体

@OneToMany(fetch = FetchType.LAZY, mappedBy = "id.license", cascade = CascadeType.ALL)

    private List<DriverLicense> driverLicense = new ArrayList<DriverLicense>();

    public List<DriverLicense> getDriverLicense() {
         return driverLicense;
    }

    public void setDriverLicense(List<DriverLicense> driverLicense) {
         this.driverLicense = driverLicense;
    }

谢谢尼克!你帮助我理解了实体的概念,等等。风格新颖。

【讨论】:

    猜你喜欢
    • 2013-10-24
    • 2013-07-22
    • 2012-05-12
    • 1970-01-01
    • 2015-03-13
    • 1970-01-01
    • 1970-01-01
    • 2018-01-01
    • 2016-06-09
    相关资源
    最近更新 更多