Как сопоставить составной ключ с Hibernate?

В этом коде как сгенерировать Java-класс для составного ключа (как составной ключ в спящем режиме):

create table Time (
     levelStation int(15) not null,
     src varchar(100) not null,
     dst varchar(100) not null,
     distance int(15) not null,
     price int(15) not null,
     confPathID int(15) not null,
     constraint ConfPath_fk foreign key(confPathID) references ConfPath(confPathID),
     primary key (levelStation, confPathID)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
188
задан David Newcomb 29 March 2019 в 04:23
поделиться

4 ответа

Для сопоставления составного ключа можно использовать аннотации EmbeddedId или и IdClass. Я знаю, что этот вопрос касается не только JPA, но также применяются правила, определенные спецификацией. Итак, вот они:

2.1.4 Первичные ключи и идентификация сущности

...

Составной первичный ключ должен соответствуют либо одному постоянное поле или свойство или в набор таких полей или свойств, как описано ниже. Класс первичного ключа должен быть определен для представления составной первичный ключ. Композитный первичные ключи обычно возникают, когда отображение из устаревших баз данных, когда ключ базы данных состоит из нескольких столбцы. EmbeddedId и Аннотации IdClass используются для обозначают составные первичные ключи. См. разделы 9.1.14 и 9.1.15.

...

Для Составные первичные ключи:

  • Класс первичного ключа должен быть общедоступным и должен иметь общедоступный параметр без аргументов. конструктор.
  • Если используется доступ на основе свойств, свойства первичного ключа класс должен быть общедоступным или защищенным.
  • Класс первичного ключа должен быть сериализуемым.
  • Класс первичного ключа необходимо определить equals и hashCode методы. Семантика значения равенство для этих методов должно быть в соответствии с равенством базы данных для типов баз данных, к которым ключ сопоставлен.
  • Составной первичный ключ должен быть представлен и отображен как встраиваемый класс (см. раздел 9.1.14, «Аннотация EmbeddedId») или должен быть представлены и сопоставлены с несколькими поля или свойства сущности class (см. Раздел 9.1.15, «IdClass Аннотация»).
  • Если составной класс первичного ключа сопоставлен с несколькими полями или свойства класса сущностей, имена полей первичного ключа или свойства в классе первичного ключа а те из класса сущностей должны соответствуют, и их типы должны быть такой же.

С IdClass

Класс составного первичного ключа может выглядеть так (может быть статическим внутренним классом):

public class TimePK implements Serializable {
    protected Integer levelStation;
    protected Integer confPathID;

    public TimePK() {}

    public TimePK(Integer levelStation, Integer confPathID) {
        this.levelStation = levelStation;
        this.confPathID = confPathID;
    }
    // equals, hashCode
}

И сущность:

@Entity
@IdClass(TimePK.class)
class Time implements Serializable {
    @Id
    private Integer levelStation;
    @Id
    private Integer confPathID;

    private String src;
    private String dst;
    private Integer distance;
    private Integer price;

    // getters, setters
}

Аннотация IdClass сопоставляет несколько полей с таблицей PK.

С EmbeddedId

Класс составного первичного ключа может выглядеть так (может быть статическим внутренним классом):

@Embeddable
public class TimePK implements Serializable {
    protected Integer levelStation;
    protected Integer confPathID;

    public TimePK() {}

    public TimePK(Integer levelStation, Integer confPathID) {
        this.levelStation = levelStation;
        this.confPathID = confPathID;
    }
    // equals, hashCode
}

И сущность:

@Entity
class Time implements Serializable {
    @EmbeddedId
    private TimePK timePK;

    private String src;
    private String dst;
    private Integer distance;
    private Integer price;

    //...
}

Аннотация @EmbeddedId сопоставляет класс PK с таблицей PK.

Различия:

  • С точки зрения физической модели различий нет
  • @EmbeddedId каким-то образом более четко сообщает, что ключ является составным ключом и ИМО имеет смысл когда комбинированный pk либо сам по себе имеет смысл, либо повторно используется в вашем коде.
  • @IdClass полезно указать, что некоторая комбинация полей уникальна, но не имеет специального значения.

Они также влияют на то, как вы пишете запросы (делая их более или менее подробными):

  • с помощью IdClass

    выберите t.levelStation из Time t
    
  • с помощью EmbeddedId

    выберите t.timePK.levelStation из времени t
    

Ссылки

  • Спецификация JPA 1.0
    • Раздел 2.1.4 «Первичные ключи и идентификатор объекта»
    • Раздел 9.1.14 «Аннотация EmbeddedId»
    • Раздел 9.1.15 «Аннотация IdClass»
401
ответ дан 23 November 2019 в 05:42
поделиться

Вам нужно использовать @EmbeddedId:

@Entity
class Time {
    @EmbeddedId
    TimeId id;

    String src;
    String dst;
    Integer distance;
    Integer price;
}

@Embeddable
class TimeId implements Serializable {
    Integer levelStation;
    Integer confPathID;
}
47
ответ дан 23 November 2019 в 05:42
поделиться

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

6
ответ дан 23 November 2019 в 05:42
поделиться

Еще один вариант — сопоставить как карту составных элементов в таблице ConfPath.

Это сопоставление выиграло бы от индекса (ConfPathID, levelStation).

public class ConfPath {
    private Map<Long,Time> timeForLevelStation = new HashMap<Long,Time>();

    public Time getTime(long levelStation) {
        return timeForLevelStation.get(levelStation);
    }

    public void putTime(long levelStation, Time newValue) {
        timeForLevelStation.put(levelStation, newValue);
    }
}

public class Time {
    String src;
    String dst;
    long distance;
    long price;

    public long getDistance() {
        return distance;
    }

    public void setDistance(long distance) {
        this.distance = distance;
    }

    public String getDst() {
        return dst;
    }

    public void setDst(String dst) {
        this.dst = dst;
    }

    public long getPrice() {
        return price;
    }

    public void setPrice(long price) {
        this.price = price;
    }

    public String getSrc() {
        return src;
    }

    public void setSrc(String src) {
        this.src = src;
    }
}

Сопоставление:

<class name="ConfPath" table="ConfPath">
    <id column="ID" name="id">
        <generator class="native"/>
    </id>
    <map cascade="all-delete-orphan" name="values" table="example"
            lazy="extra">
        <key column="ConfPathID"/>
        <map-key type="long" column="levelStation"/>
        <composite-element class="Time">
            <property name="src" column="src" type="string" length="100"/>
            <property name="dst" column="dst" type="string" length="100"/>
            <property name="distance" column="distance"/>
            <property name="price" column="price"/>
        </composite-element>
    </map>
</class>
2
ответ дан 23 November 2019 в 05:42
поделиться
Другие вопросы по тегам:

Похожие вопросы: