简体   繁体   English

JPA 2.0(Hibernate)使用@JoinTable为@OneToMany生成了不正确的联接表PK

[英]JPA 2.0 (Hibernate) generates incorrect join table PK for @OneToMany with @JoinTable

I've using JPA 2.0 with Hibernate 4.3.5 and trying to use Hibernate to auto generate my tables. 我在Hibernate 4.3.5中使用了JPA 2.0,并试图使用Hibernate自动生成我的表。

I've created the following entry in my Contact entity: 我在联系人实体中创建了以下条目:

/**
 * Address
 */
@Valid
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JoinTable(name = "contact_address", joinColumns = @JoinColumn(name = "contact_id", referencedColumnName = "id"), inverseJoinColumns = @JoinColumn(name = "address_id", referencedColumnName = "id"))
@OrderColumn
private List<Address> addresses;

Hibernate is properly creating the contact table, but the join table is created without the correct PK: Hibernate可以正确创建联系人表,但是创建联接表时没有正确的PK:

CREATE TABLE `contact_address` (
  `contact_id` bigint(20) NOT NULL,
  `address_id` bigint(20) NOT NULL,
  `addresses_order` int(11) NOT NULL,
  PRIMARY KEY (`contact_id`),
  UNIQUE KEY `UK_mvvtppjfu6d0lcjm83u5youn8` (`address_id`),
  CONSTRAINT `FK_4fntyt0q2l6vkfg7t38pg4i94` FOREIGN KEY (`contact_id`) REFERENCES `contact` (`id`),
  CONSTRAINT `FK_mvvtppjfu6d0lcjm83u5youn8` FOREIGN KEY (`address_id`) REFERENCES `address` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

The PK listed here is only the contact_id , which is incorrect. 此处列出的PK只是contact_id ,这是不正确的。 That will not allow me to have multiple addresses assigned. 那将不允许我分配多个地址。 Rather, the PK should be a composite PK of contact_id , address_id . 而是,PK应该是contact_idaddress_id的复合PK。

Is Hibernate at fault, or is there something wrong in my JPA annotation? Hibernate是否有故障,或者我的JPA批注中有问题? This is a one-way association. 这是一种单向关联。

As noted by a couple of people, technically speaking, I don't need a join table for a @OneToMany, but given that I need to use the Address entity in other entity objects, it is cleaner for me to use join tables for all the associations. 正如一些人指出的那样,从技术上来说,我不需要@OneToMany的联接表,但是鉴于我需要在其他实体对象中使用Address实体,因此对于所有对象使用联接表对我来说更干净协会。

I have managed to hack around a solution using the @ManyToMany association and specifying a unique constraint on the join columns, but I am trying to understand if there is something wrong with my JPA or if it is a Hibernate bug. 我已经设法使用@ManyToMany关联并在连接列上指定了唯一约束来解决一个问题,但是我试图了解我的JPA是否有问题或它是否是Hibernate错误。

If you need One To Many relationship between Contact and Address where one contact has many addresses. 如果您需要“联系人”和“地址”之间的一对多关系,其中一个联系人有多个地址。 Following will suffice without an associative table. 没有关联表就可以满足以下条件。

@Valid
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
@JoinColumn(name="contact_id", referencedColumnName="id")
private List<Address> addresses;

You need to add more details to your question. 您需要为问题添加更多详细信息。 For example, how have you annotated the Address entity? 例如,您如何注释Address实体?

Anyway, if you annotate and define your entities correctly, Hibernate will generate the tables correctly for you: 无论如何,如果您正确注释和定义了实体,则Hibernate将为您正确生成表:

@Entity
public class Contact {

    @Id
    @GeneratedValue(generator = "UUID")
    @GenericGenerator(
            name = "UUID",
            strategy = "org.hibernate.id.UUIDGenerator"
    )
    private String id;

    private String fullName;

    @OneToMany(cascade = CascadeType.ALL)
    @JoinTable(
            name = "contact_addresses",
            joinColumns = @JoinColumn(
                    name = "contact_id",
                    referencedColumnName = "id"
            ),
            inverseJoinColumns = @JoinColumn(
                    name = "address_id",
                    referencedColumnName = "id"
            )
    )
    private Set<Address> addresses = new HashSet<>();

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getFullName() {
        return fullName;
    }

    public void setFullName(String brand) {
        this.fullName = brand;
    }

    public Set<Address> getAddresses() {
        return addresses;
    }

    public void setAddresses(Set<Address> contacts) {
        this.addresses = addresses;
    }

    public void addAddress(Address address) {
        getAddresses().add(address);
        address.setContact(this);
    }
}

@Entity
public class Address {

    @Id
    @GeneratedValue(generator = "UUID")
    @GenericGenerator(
            name = "UUID",
            strategy = "org.hibernate.id.UUIDGenerator"
    )
    private String id;

    private String streetAddress;

    @ManyToOne(cascade = CascadeType.ALL)
    private Contact contact;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getStreetAddress() {
        return streetAddress;
    }

    public void setStreetAddress(String name) {
        this.streetAddress = name;
    }

    public Contact getContact() {
        return contact;
    }

    public void setContact(Contact contact) {
        this.contact = contact;
    }
}

Here's a sample test case: 这是一个示例测试用例:

@Test
public void testContactAddresses() {
    EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("ContactAddresses");
    EntityManager entityManager = entityManagerFactory.createEntityManager();
    EntityTransaction transaction = entityManager.getTransaction();
    transaction.begin();

    Contact contact = new Contact();
    contact.setFullName("Steve Ballmer");

    Address address1 = new Address();
    address1.setStreetAddress("Developers Street");

    Address address2 = new Address();
    address2.setStreetAddress("Developers Developers Street");

    Address address3 = new Address();
    address3.setStreetAddress("Developers Developers Developers Street");

    contact.addAddress(address1);
    contact.addAddress(address2);
    contact.addAddress(address3);

    entityManager.persist(contact);

    transaction.commit();
}

And here are the DDL statements executed by Hibernate: 这是Hibernate执行的DDL语句:

Hibernate: drop table Address if exists
Hibernate: drop table Contact if exists
Hibernate: drop table contact_addresses if exists
Hibernate: create table Address (id varchar(255) not null, streetAddress varchar(255), contact_id varchar(255), primary key (id))
Hibernate: create table Contact (id varchar(255) not null, fullName varchar(255), primary key (id))

Hibernate: create table contact_addresses (
    contact_id varchar(255) not null, 
    address_id varchar(255) not null, 
    primary key (contact_id, address_id)
)

Hibernate: alter table contact_addresses add constraint UK_mxmb2y0iu8624h4rrdamayobp unique (address_id)
Hibernate: alter table Address add constraint FK98iji1i9ycae5a36rman0vd17 foreign key (contact_id) references Contact
Hibernate: alter table contact_addresses add constraint FK6n27pwv86i3cx03jv3i9taidw foreign key (address_id) references Address
Hibernate: alter table contact_addresses add constraint FKmw2sdpyxrxj3obg1x1ltdlwbo foreign key (contact_id) references Contact

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM