【问题标题】:Issue with Mysql auto generated PK used for another table and JPA用于另一个表和 JPA 的 Mysql 自动生成的 PK 问题
【发布时间】:2012-02-12 09:57:18
【问题描述】:

我的用例如下:我使用 MySQL 和 JPA 2,我有两个实体:OrderLineItem,它们通过 OneToMany 关系关联。

我希望 GUI 层同时将 Order 与 LineItem 一起保存。

记住 Order 的 PK 是 MySQL 自动生成的,并且 是 LineItem 的 PK 的一部分,我不知道如何检索生成的订购 PK 以便在同一事务中将其用于 LineItem PK。

有人可以帮忙吗?

根据您的反馈,这里有一些来自实体的示例代码(实际上是我在上面编写了用例/域。我的更复杂,所以您不会看到任何 Order 或 LineItem)。

@Entity
@Table(name = "advertisement")
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name = "status_need_ID", discriminatorType = DiscriminatorType.INTEGER)
@NamedQueries({
    @NamedQuery(name = "Advertisement.findAll", query = "SELECT a FROM Advertisement a"),
    @NamedQuery(name = "Advertisement.findByAdvertisementID", query = "SELECT a FROM Advertisement a WHERE a.advertisementID = :advertisementID"),
    @NamedQuery(name = "Advertisement.findByAdvertisementTitle", query = "SELECT a FROM Advertisement a WHERE a.advertisementTitle = :advertisementTitle"),
    @NamedQuery(name = "Advertisement.findByAdvertisementCreationDate", query = "SELECT a FROM Advertisement a WHERE a.advertisementCreationDate = :advertisementCreationDate"),
    @NamedQuery(name = "Advertisement.findByStatusneedID", query = "SELECT a FROM Advertisement a WHERE a.statusneedID = :statusneedID")})
public class Advertisement implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Basic(optional = false)
    @Column(name = "advertisement_ID", nullable = false)
    private Integer advertisementID;
    @Basic(optional = false)
    @Column(name = "advertisement_title", nullable = false, length = 200)
    private String advertisementTitle;
    @Column(name = "advertisement_creation_date")
    @Temporal(TemporalType.TIMESTAMP)
    private Date advertisementCreationDate;
    @Basic(optional = false)
    @Lob
    @Column(name = "advertisement_body", nullable = false, length = 2147483647)
    private String advertisementBody;
    @Column(name = "status_need_ID")
    private Integer statusneedID;
    @JoinTable(name = "postcode_to_advertisement_join", joinColumns = {
        @JoinColumn(name = "advertisement_ID", referencedColumnName = "advertisement_ID", nullable = false)}, inverseJoinColumns = {
        @JoinColumn(name = "postcode_ID", referencedColumnName = "postcode_ID", nullable = false)})
    @ManyToMany
    private Collection<Postcode> postcodeCollection;
    @JoinTable(name = "advertisement_to_duration_join", joinColumns = {
        @JoinColumn(name = "advertisement_ID", referencedColumnName = "advertisement_ID", nullable = false)}, inverseJoinColumns = {
        @JoinColumn(name = "duration_ID", referencedColumnName = "duration_ID", nullable = false)})
    @ManyToMany
    private Collection<Duration> durationCollection;
    @JoinTable(name = "full_or_part_time_basis_to_advertisement_join", joinColumns = {
        @JoinColumn(name = "advertisement_ID", referencedColumnName = "advertisement_ID", nullable = false)}, inverseJoinColumns = {
        @JoinColumn(name = "full_or_part_time_basis_ID", referencedColumnName = "full_or_part_time_basis_ID", nullable = false)})
    @ManyToMany
    private Collection<FullOrPartTimeBasis> fullOrPartTimeBasisCollection;
    @JoinTable(name = "advertisement_to_child_care_type_join", joinColumns = {
        @JoinColumn(name = "advertisement_ID", referencedColumnName = "advertisement_ID", nullable = false)}, inverseJoinColumns = {
        @JoinColumn(name = "child_care_type_ID", referencedColumnName = "child_care_type_ID", nullable = false)})
    @ManyToMany
    private Collection<ChildCareType> childCareTypeCollection;
    @JoinTable(name = "advertisement_to_school_holiday_join", joinColumns = {
        @JoinColumn(name = "advertisement_ID", referencedColumnName = "advertisement_ID", nullable = false)}, inverseJoinColumns = {
        @JoinColumn(name = "school_holiday_ID", referencedColumnName = "school_holiday_ID", nullable = false)})
    @ManyToMany
    private Collection<SchoolHoliday> schoolHolidayCollection;
    @JoinTable(name = "employment_contract_to_advertisement_join", joinColumns = {
        @JoinColumn(name = "advertisement_ID", referencedColumnName = "advertisement_ID", nullable = false)}, inverseJoinColumns = {
        @JoinColumn(name = "employment_contract_ID", referencedColumnName = "employment_contract_ID", nullable = false)})
    @ManyToMany
    private Collection<EmploymentContract> employmentContractCollection;
    @OneToMany(cascade = CascadeType.ALL, mappedBy = "advertisement")
    private Collection<AdvertisementToTimeSlotToDayJoin> advertisementToTimeSlotToDayJoinCollection;
    @OneToMany(cascade = CascadeType.ALL, mappedBy = "advertisementID")
    private Collection<Salary> salaryCollection;
    @OneToOne(cascade = CascadeType.ALL, mappedBy = "advertisement")
    private ParentToParentAdvertisement parentToParentAdvertisement;
    @OneToOne(cascade = CascadeType.ALL, mappedBy = "advertisement")
    private ParentToChildMinderAdvertisement parentToChildMinderAdvertisement;
    @JoinColumn(name = "child_care_location_ID", referencedColumnName = "child_care_location_ID", nullable = false)
    @ManyToOne(optional = false)
    private ChildCareLocation childcarelocationID;
    @JoinColumn(name = "account_ID", referencedColumnName = "account_ID", nullable = false)
    @ManyToOne(optional = false)
    private Account accountID;



@Entity
@Table(name = "advertisement_to_time_slot_to_day_join",schema="bignibou")
@NamedQueries({
    @NamedQuery(name = "AdvertisementToTimeSlotToDayJoin.findAll", query = "SELECT a FROM AdvertisementToTimeSlotToDayJoin a"),
    @NamedQuery(name = "AdvertisementToTimeSlotToDayJoin.findByDayID", query = "SELECT a FROM AdvertisementToTimeSlotToDayJoin a WHERE a.advertisementToTimeSlotToDayJoinPK.dayID = :dayID"),
    @NamedQuery(name = "AdvertisementToTimeSlotToDayJoin.findByTimeslotID", query = "SELECT a FROM AdvertisementToTimeSlotToDayJoin a WHERE a.advertisementToTimeSlotToDayJoinPK.timeslotID = :timeslotID"),
    @NamedQuery(name = "AdvertisementToTimeSlotToDayJoin.findByAdvertisementID", query = "SELECT a FROM AdvertisementToTimeSlotToDayJoin a WHERE a.advertisementToTimeSlotToDayJoinPK.advertisementID = :advertisementID")})
public class AdvertisementToTimeSlotToDayJoin implements Serializable {
    private static final long serialVersionUID = 1L;
    @EmbeddedId
    protected AdvertisementToTimeSlotToDayJoinPK advertisementToTimeSlotToDayJoinPK;
    @JoinColumn(name = "time_slot_ID", referencedColumnName = "time_slot_ID", nullable = false, insertable = false, updatable = false)
    @ManyToOne(optional = false)
    private TimeSlot timeSlot;
    @JoinColumn(name = "day_ID", referencedColumnName = "day_ID", nullable = false, insertable = false, updatable = false)
    @ManyToOne(optional = false)
    private Day day;
    @JoinColumn(name = "advertisement_ID", referencedColumnName = "advertisement_ID", nullable = false, insertable = false, updatable = false)
    @ManyToOne(optional = false)
    private Advertisement advertisement;

【问题讨论】:

  • 可以添加实体映射的代码吗?
  • 谢谢。做你在 JPA 中描述的怎么样?有可能吗?

标签: mysql primary-key jpa-2.0 auto-generate


【解决方案1】:

这里的基本思想是您必须分两个阶段保存您的实体。当然,您可以在同一事务中执行此操作。首先,您保存您的订单,而不保存 LineItem(s),然后检索 PK(如果是 Order),然后将其设置在 LineItem(s) 上,然后保存 LineItem(s)。我猜是 OneToMany 注释的 CascadeType 属性将告诉 JPA 在两个不同的阶段执行此操作,即在保存订单时不保存 LineItems。像这样的:

@Entity
public class Order {
    @Id 
    @GeneratedValue(strategy=GenerationType.AUTO) 
    long id;

    @OneToMany(cascade={})
    Set<LineItem> lineItems;
}

或者您可以在保存订单时将lineItems设置为空,然后检索PK,设置lineItems和lineItems的PK,然后再次保存订单。

如果您的数据库设计是最终设计并且您无法更改,请忽略这部分答案。

这是我个人的意见(基于多年的数据库设计和维护)。那么,首先,您是否有充分的理由在 LineItem 中使用复合 PK 而不是使用旧的 surrogate primary key

因为如果您不这样做,那么您应该在 LineItem 中有一个代理主键。否则你会不断遇到各种问题(例如,如果你碰巧必须迁移数据)

编辑我的建议:

  1. 在数据库中:在您的表中使用 auto_increment PK,如本例所示:http://dev.mysql.com/doc/refman/5.0/en/example-auto-increment.html
  2. 在 JPA 映射中:选择本文中的第一个选项 (AUTO):http://www.objectdb.com/java/jpa/entity/generated

【讨论】:

  • 1.我很确定有一种方法可以通过 JPA 配置来解决这个问题。也许我应该使用带有分隔表的@TableGenerator?那会是一个很好的代理键吗?还是您建议我使用 UUID?
  • 我看不出有任何理由在这里使用@TableGenerator。在这种情况下,我不明白 UUID 是什么意思。我的建议已添加到答案的末尾。
  • 感谢您的回复,但问题不在于生成数字,而是将生成的数字用于第二个表。你明白我的意思吗?因此,您建议的链接有些无关紧要。
  • 我明白你的意思,我回答的第一部分是为了帮助你实现目标。第二部分虽然有链接,但我建议放弃最初的目标并正确地做到这一点。
猜你喜欢
  • 1970-01-01
  • 2015-10-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-07
  • 2018-04-25
  • 2011-09-12
相关资源
最近更新 更多