Таблица JPA с 2 полями первичного ключа

У меня есть таблица, содержащая только 2 поля. Таблица имеет составной PK, образованный этими двумя полями.

При использовании NetBeans для создания сущности beans из базы данных объект bean не создается автоматически, как другие таблицы с более чем двумя полями.

Итак, мне нужно создать сущность bean самостоятельно. Какова наилучшая практика для создания этого объекта bean? Должен ли он содержать объект COMPOSITE KEY или нет?

Ответ 1

Я не использую NetBeans, поэтому я ничего не могу сказать о его инструментах отображения.

Для отображения составного ключа есть несколько вариантов. Вы можете

  • Определите отдельный объект @Embeddable с полями PK и используйте его как @EmbeddedId в вашем классе @Entity

    @Embeddable
    public class MyCompositePK { 
        @Column
        private String fieldA;
        @Column
        private String fieldB;
    }
    @Entity 
    public class MyBean { 
        @EmbeddedId
        private MyCompositePK id;
        @Column
        private String fieldC;
    }
    
  • Определите неотображенное POJO с полями PK и используйте его как @IdClass в @Entity.

    @Entity
    @IdClass(value=ClassAB.ClassABId.class)
    public class ClassAB implements Serializable {
        private String idA;
        private String idB;
    
        @Id
        @Column(name="ID_A")
        public String getIdA(){ return idA; }
        public void setIdA(String idA){ this.idA = idA; }
    
        @Id
        @Column(name="ID_B")
        public String getIdB(){ return idB; }
        public void setIdB(String idB){ this.idB = idB; }
    
        static class ClassABId implements Serializable {
            private String idA;
            private String idB;
    
            public String getIdA(){ return idA; }
            public void setIdA(String idA){ this.idA = idA; }
    
            public String getIdB(){ return idB; }
            public void setIdB(String idB){ this.idB = idB; }
    
            // implement equals(), hashcode()
        }
    }
    

    В этом примере ClassABId является статическим внутренним классом только для удобства.

Эти параметры также объясняются в Pascal Thivent превосходным ответом на этот вопрос: Как сопоставить составной ключ с Hibernate?.

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

Во всяком случае, я не думаю, что есть альтернатива созданию двух классов. Вот почему я задал этот вопрос: Сопоставление класса, состоящего только из составного ПК без @IdClass или @EmbeddedId. Кажется, для этой функции существует функция спящего режима.

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

Ответ 2

Спасибо @XaviLópez. Ваше объяснение установило мой код, который был объявлен как его собственный IdClass, упомянутый @Tom Anderson. Когда я объявлял его собственным IdClass, имеющим 2 столбца @Id, запрос JPA, получающий список этого объекта, возвращал ожидаемые "n" элементы в списке результатов, но каждый элемент в этом списке был нулевым. Но этот размер "n" ожидается. После перехода на статический внутренний класс, который меньше рефакторинга, он способен возвращать правильный набор результатов.

По мне: самореклама IdClass не будет работать, потому что я уже являюсь сущностью и должен находиться в Контрастности. Если у меня также есть первичный ключевой объект того же типа, тогда в контексте персистентности будут два идентичных объекта. Поэтому его не следует допускать. Следовательно, мы не должны использовать самостоятельную привязку @IdClass. Создайте статический внутренний класс как тип первичного ключа, который менее навязчив.