Ошибка с автоматически сгенерированным ПК Mysql, используемым для другой таблицы и JPA - PullRequest
0 голосов
/ 17 января 2012

Мой пример использования следующий: я использую MySQL и JPA 2, и у меня есть две сущности: Order и LineItem , которые связаны отношением OneToMany.

Я бы хотел, чтобы слой с графическим интерфейсом сохранил Order вместе с LineItem одновременно.

Учитывая, что PK порядка автоматически генерируется MySQL, а является частью PK LineItem , я не знаю, как получитьсгенерированный PK заказа, чтобы использовать его для PK LineItem в той же транзакции.

Может кто-нибудь помочь, пожалуйста?

В дополнение к вашему отзыву, вот пример кода от сущностей (я на самом делеПриведенный выше вариант использования / домен. Мой более сложный, поэтому вы не увидите ни 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;

1 Ответ

2 голосов
/ 17 января 2012

Основная идея в том, что вам придется сохранять свои сущности в два этапа. Конечно, вы можете сделать это в той же транзакции. Сначала вы сохраняете свой Заказ, не сохраняя LineItem, затем извлекаете PK, если Заказ, затем устанавливаете его на LineItem, а затем сохраняете LineItem. Я предполагаю, что это свойство CascadeType аннотации OneToMany, которое скажет JPA сделать это в два разных этапа, а не сохранять LineItems при сохранении ордера. Примерно так:

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

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

Или можно сохранить пустыми lineItems при сохранении Order, затем получить PK, установить lineItems и PK для lineItems, а затем снова сохранить Order.

Не обращайте внимания на эту часть ответа, если ваш дизайн базы данных окончательный и вы не можете его изменить.

Это мое личное мнение (основанное на многолетней разработке и обслуживании базы данных). Итак, во-первых, у вас есть веская причина для использования составного PK в LineItem вместо использования старого доброго суррогатного первичного ключа ?

Потому что, если вы этого не сделаете, у вас должен быть суррогатный первичный ключ в LineItem. В противном случае вы будете сталкиваться с различными проблемами (например, если вам придется переносить данные)

РЕДАКТИРОВАТЬ Мое предложение:

  1. в БД: используйте auto_increment PK в ваших таблицах, как в этом примере: http://dev.mysql.com/doc/refman/5.0/en/example-auto-increment.html
  2. в отображении JPA: выберите первый вариант (АВТО) в этой статье: http://www.objectdb.com/java/jpa/entity/generated
...