2010-10-30 2 views
1

Учитывая следующий пример (отделы - проекты):Ограничение JPA 1.0 с использованием @IdClass с * вложенными * составными первичными ключами?

Отдел имеет следующие свойства (составной первичный ключ):

@Entity 
@IdClass(DeptId.class) 
public class Department 
{ 
    @Id 
    @Column(name="number") 
    private Integer number; 

    @Id 
    @Column(name="country") 
    private String country; 

    @Column(name="name") 
    private String name; 

    @OneToMany(mappedBy="dept") 
    private Collection<Project> projects; 

    ... 
} 

Здесь класс PK:

public class DeptId implements Serializable 
{ 
    private Integer number; 
    private String country; 

    ... 
} 

Отношения между проекты и отделы - это много-к-одному, то есть у департамента есть много проектов. Класс Project сам использует составной ключ для композитного ключевого слова. Важное примечание: речь идет только о реализации с @IdClass не @EmbeddedId.

Тогда реализация (проблематичный) JPA 1.0 @IdClass придется искать что-то подобное (избыточный столбец DEPTNUM и свойство deptCtry): -> это просто уникальное имя в пределах отдела

@Entity 
@IdClass(ProjectId.class) 
public class Project 
{ 
    @Id 
    @Column(name="dept_number") 
    private Integer deptNumber; 

    @Id 
    @Column(name="dept_country") 
    private String deptCountry; 

    @Id 
    @Column(name="name") 
    private String name; 

    @ManyToOne 
    @JoinColumns({ 
     @JoinColumn(name="dept_number", referencedColumnName="number"), 
     @JoinColumn(name="dept_country", referencedColumnName="country") 
    })  
    private Department dept; 

    ... 
} 

ProjectID является:

public class ProjectId implements Serializable 
{ 
    private String name; 
    private DeptId dept; 

    ... 
} 

проблема с этим состоит в том, что ни Hibernate, ни EclipseLink узнать, как отобразить два избыточных свойств столбца DEPTNUM и deptCtry в проекте на имущество DEPT в DeptId (или внутри него Недвижимость Болгария Недвижимость). -> MappingException и т.д.

Мой вопрос:

Является ли это ограничение JPA 1.0, что таблицы с составными ключами, ссылающихся другие ключи композитных с реализациями @IdClass вообще не будет работать, поскольку осуществление JPA просто не можете знать, как сопоставить эти поля?

В качестве обходного пути вам необходимо использовать @EmbeddedId для этих классов или использовать синтаксис JPA 2.0 для аннотации ассоциаций @XToX с помощью @Id. Я просто хочу убедиться, что мой взгляд на это прав.

Благодаря

ответ

2

Проблема с посланным кодом, что JPA 1.0 действительно не позволяет вложенности составных первичных ключей классов.Это ProjectID недействителен:

public class ProjectId implements Serializable 
{ 
    private String name; 
    private DeptId dept; 

    ... 
} 

DeptId должна быть плоской, как:

public class ProjectId implements Serializable 
{ 
    private Integer deptNumber; 
    private String deptCountry; 
    private String name; 

    ... 
} 

Я только что получил версию EclipseLink идти, но Hibernate имеет проблемы с этим. Интересно, как сказать Hibernate, что JPA 1.0 предполагается.

2

Проблема с этим состоит в том, что ни Hibernate, ни EclipseLink узнать, как отобразить два избыточные свойства столбца DEPTNUM и deptCtry в проекте на имущество DEPT в DeptId

Это почему вам нужно определить внешний ключ ManyToOne как только для чтения с таким видом сопоставления. Это делается путем установки атрибутов JoinColumninsertable и updatable - false.

Так попробуйте следующее:

@Entity 
@IdClass(ProjectId.class) 
public class Project 
{ 
    @Id 
    @Column(name="dept_number") 
    private Integer deptNumber; 

    @Id 
    @Column(name="dept_country") 
    private String deptCountry; 

    @Id 
    @Column(name="name") 
    private String name; 

    @ManyToOne 
    @JoinColumns({ 
     @JoinColumn(name="dept_number", referencedColumnName="number", insertable=false, updatable=false), 
     @JoinColumn(name="dept_country", referencedColumnName="country", insertable=false, updatable=false) 
    })  
    private Department dept; 
    ... 
} 
+0

Речь идет не о вставном/обновляемом материале. Как ORM узнают, какие свойства карты dept_x ProjectId? Я не работаю с обоими ... Hibernate AND EL. Они уже терпят неудачу, когда EntityManagerFactory создается. Это имеет смысл ... – Kawu

+0

@Kawu: Может быть, я не понимаю, что вы говорите, но когда вы повторяете сопоставления, как показано выше, вы должны сделать связь только для чтения, используя insertable/updatable в 'JoinColumn'. Если это не сработает, покажите сопоставление, позволяющее воспроизвести и некоторые следы, иллюстрирующие проблему. –

+0

Позвольте мне пояснить это: JPA 1.0 не позволяет @Id об ассоциациях, поэтому в Project у вас есть два избыточных члена deptNumber и deptCountry. Поскольку эти два являются PK в таблице Departments, составной ключевой класс Project ProjectId имеет член типа DeptId. Но Hibernate и EclipseLink оба бросают отображение исключений, потому что они не могут сопоставить два избыточных элемента @Id members deptNumber и deptCountry с свойствами DeptId. Я хотел знать, является ли это общим ограничением, или если есть способ сообщить ORM JPA 1.0 как их сопоставить. (JPA 1.0 требует, чтобы имена полей совпадали) – Kawu

3

Да, это ограничение JPA 1.0, исправленное в JPA 2.0. В новом JPA 2.0 вы можете поместить аннотацию ID в свои отношения dept и полностью избежать наличия избыточных атрибутов deptCountry и deptNumber с классом ключей с использованием вложенности. В JPA 1.0 только базовые сопоставления могут быть отмечены как отдельно от идентификатора, требующие избыточных сопоставлений и некоторого кода, чтобы гарантировать, что значения/отношения будут корректно помещены в кеш при сохранении. Из-за избыточности, как упоминалось в других ответах, одно из сопоставлений для поля должно быть помечено только для чтения через insertable/updatable = false. Однако это означает, что значение не сливается в кеш, поэтому изменения (например, вставки, поскольку вы не можете изменить идентификатор объектов после его существования) не будут отражаться, если объект не обновлен из базы данных. Если вы помечаете JoinColumns как только для чтения, вам нужно будет получить значения из ссылочного департамента и поместить их в соответствующие исходные атрибуты идентификатора вручную, когда вы хотите сохранить проект. Но вы также можете пометить основные атрибуты как доступные только для чтения. Eclipselink в любом случае не будет иметь никаких проблем и будет корректно устанавливать значения полей с помощью связанного объекта dept (до тех пор, пока он установлен до того, как в Project будет вызываться persist). Обратите внимание, что основные атрибуты могут быть заполнены или не заполнены при чтении проекта в другом контексте - это будет зависеть от того, обновляется ли объект из базы данных или нет. Если они доступны только для чтения, они не объединяются в общий кэш, поскольку они, только для чтения, не должны меняться. Таким образом, их можно просто игнорировать, или если они должны быть заполнены, объект обновляется или значения, установленные из отдела в событии.

Эта же модель может быть использована повторно с помощью JPA2.0 @MapsId, которая также будет поддерживать основные сопоставления, используя значения из отношения для вас. Единственное, что я вижу, это то, что вам не нужно получать доступ к отношениям (потенциально вызывающим ненужные соединения или доступ к базе данных по ленивым отношениям), чтобы получить значения полей внешнего ключа/идентификатора.

Что касается исключений ZipArea EclipseLink, они обусловлены тем, что ZipAreaId имеет атрибут zipId zip, вместо этого он сглаживается. JPA 1.0 требует, чтобы класс ключа имел атрибут того же типа и имени для каждого атрибута @ID в Entity.

Смежные вопросы