В моей базе данных есть две сущности; Компания и Персона. Компания может иметь много людей, но у человека должна быть только одна компания. Структура таблицы выглядит следующим образом.
COMPANY
----------
owner PK
comp_id PK
c_name
PERSON
----------------
owner PK, FK1
personid PK
comp_id FK1
p_fname
p_sname
Мне пришло в голову, что я могу удалить PERSON.OWNER и получить его через внешний ключ; однако я не могу внести это изменение, не затронув устаревший код.
Я смоделировал их как JPA-аннотированные классы;
@Entity
@Table(name = "PERSON")
@IdClass(PersonPK.class)
public class Person
implements Serializable {
@Id
private String owner;
@Id
private String personid;
@ManyToOne
@JoinColumns(
{@JoinColumn(name = "owner", referencedColumnName = "OWNER",
insertable = false, updatable = false),
@JoinColumn(name = "comp_id", referencedColumnName = "COMP_ID",
insertable = true, updatable = true)})
private Company company;
private String p_fname;
private String p_sname;
...and standard getters/setters...
}
@Entity
@Table(name = "COMPANY")
@IdClass(CompanyPK.class)
public class Company
implements Serializable {
@Id
private String owner;
@Id
private String comp_id;
private String c_name;
@OneToMany(mappedBy = "company", cascade=CascadeType.ALL)
private List people;
...and standard getters/setters...
}
Мои классы PersonPK и CompanyPK не являются чем-то особенным, они просто служат держателем структуры и полем ID и переопределяют hashCode и равны (o).
Пока все хорошо. Однако я сталкиваюсь с проблемой при попытке разобраться с ассоциациями. Кажется, что если у меня есть существующая Компания, и я создаю Лицо, и связываю Лица с Компанией, и сохраняю компанию, ассоциация не сохраняется при вставке Лица. Например, мой основной код выглядит так:
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
CompanyPK companyPK = new CompanyPK();
companyPK.owner="USA";
companyPK.comp_id="1102F3";
Company company = em.find(Company.class, companyPK);
Person person = new Person();
person.setOwner("USA");
person.setPersonid("5116628123"); //some number that doesn't exist yet
person.setP_fname("Hannah");
person.setP_sname("Montana");
person.setCompany(company);
em.persist(person);
Это завершается без ошибок; однако в базе данных я обнаружил, что запись Person была вставлена с нулем в поле COMP_ID. Если для журнала отладки EclipseLink задано значение FINE, запрос SQL отображается в виде:
INSERT INTO PERSON (PERSONID,OWNER,P_SNAME,P_FNAME) VALUES (?,?,?,?)
bind => [5116628123,USA,Montana,Hannah,]
Я ожидал, что это будет сохранено, и запрос будет эквивалентен
INSERT INTO PERSON (PERSONID,OWNER,COMP_ID,P_SNAME,P_FNAME) VALUES (?,?,?,?,?)
bind => [5116628123,USA,1102F3,Montana,Hannah,]
Что дает? Неверно ли говорить, что Updatable / Inserttable = true для одной половины составного ключа и = false для другой половины? Если у меня есть Updatable / Inserttable = true для обеих частей внешнего ключа, то Eclipselink не запускается, говоря, что я не могу использовать столбец дважды, если у меня не установлен один параметр только для чтения, указав эти параметры.