Nano Hash - криптовалюты, майнинг, программирование

JPA, Hibernate, могу ли я сделать составной первичный ключ, один из элементов которого является внешним кеем @OneToMany?

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

Я пишу что-то вроде этого, но не знаю, работает ли это, потому что внешний ключ помечен как сгенерированное значение в источнике данных IntelliJ

@Entity
@Table(name = "service_point")
@Access(AccessType.PROPERTY)
@IdClass(ServicePointId.class)
public class ServicePoint {

    private Long providerId;
    private Integer servicePointNumber;

    private Provider provider;

    @Id
    @Basic(optional = false)
    @Column(name = "provider_id", nullable = false, insertable = false,
            updatable = false, columnDefinition = "BIGINT UNSIGNED")
    public Long getProviderId() {
        return providerId;
    }

    public void setProviderId(Long providerId) {
        this.providerId = providerId;
    }

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Basic(optional = false)
    @Column(name = "service_point_no", nullable = false, columnDefinition = "BIGINT UNSIGNED")
    public Integer getServicePointNumber() {
        return servicePointNumber;
    }

    public void setServicePointNumber(Integer servicePointNumber) {
        this.servicePointNumber = servicePointNumber;
    }

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "provider_id")
    public Provider getProvider() {
        return provider;
    }

    public void setProvider(Provider provider) {
        this.provider = provider;
    }
}

ОБНОВЛЕНО:

Я протестировал Брайана Восбурга, и он работает:

transaction.begin();

em.persist(provider);

ServicePoint servicePoint = new ServicePoint(provider, 1);

em.persist(servicePoint);

transaction.commit();

ServicePoint servicePoint2 = em.find(ServicePoint.class,
        new ServicePointId(provider.getUserId(), servicePoint.getServicePointNumber()));

assertTrue("Service point provider id and Provider provider id should be the same.",
        servicePoint2.getProvider().getUserId() == provider.getUserId());
assertNotNull("Service point number can not be null", servicePoint2.getServicePointNumber());
assertEquals(servicePoint2.getProvider(), provider);

transaction.begin();
em.remove(servicePoint);
em.remove(provider);
transaction.commit();

ОБНОВЛЕНИЕ 2 - новая проблема в составном PK следующего отношения (3 столбца), а 2 из них являются составными FK. Я пытался походить на приведенное ниже решение и не мог понять, как написать ServicePointPhotoId @IdClass

расширения предыдущего примера


Ответы:


1

Избавьтесь от поля providerId и соответствующих ему геттеров и сеттеров. Добавьте аннотацию @Id к getProvider(). Определите IdClass следующим образом:

public class ServicePointId {
    private Long provider;
    private Integer servicePointNumber;
    public Integer getProvider() {
        return provider;
    }
    public void setProvider(Integer provider) {
        this.provider = provider;
    }
    public Integer getServicePointNumber() {
        return servicePointNumber;
    }
    public void setServicePointNumber(Integer servicePointNumber) {
        this.servicePointNumber = servicePointNumber;
    }
}

Обратите внимание, что имя свойства в IdClass совпадает с именем свойства в Entity (т.е. provider), но типы свойств разные. В IdClass тип свойства должен совпадать с типом свойства Id в Provider.

Это обсуждается в спецификации JPA 2.1, раздел 2.4.1.

Предложение для ОБНОВЛЕНИЯ 2:

public class ServicePointPhotoId {
    public ServicePointId servicePoint;
    public Long photoId;
}

@Entity
@IdClass(ServicePointPhotoId.class)
@Table(name="service_point_photo")
public class ServicePointPhoto {
    @Id
    @ManyToOne
    @JoinColumns({
        @JoinColumn(name="provider_id", referencedColumnName="provider_id"),
        @JoinColumn(name="service_point_no", referencedColumnName="service_point_no")
    })
    private ServicePoint servicePoint;

    @Id
    @Column(name="photo_id")
    private Long photoId;
}

Обратите внимание, что имя атрибута должно совпадать (например, servicePoint); но тип атрибута IdClass должен соответствовать ссылочному Entity IdClass (т.е. ServicePointId).

Я использовал аннотации полей, но вы можете преобразовать их в аннотации свойств.

Опять же: в спецификации JPA 2.1 есть пример именно такого рода отношений в разделе 2.4.1.3.

09.06.2015
  • Я тестирую это решение и думаю, есть ли возможность сделать что-то вроде: 1) em.persist(provider); ServicePoint servicePoint = новая точка обслуживания (поставщик); em.persist (точка обслуживания); и автоматически генерируется только servicePointNumber. 2) Могу ли я остаться в IdClass providerId и использовать @MapsId(provider_id) для провайдера в ServicePoint? 09.06.2015
  • Хорошо, это решение, похоже, работает правильно. Не могли бы вы сказать мне, будет ли такой подход приемлемым или лучше будет использовать .@EmbeddedId вместо @IdClass. Если я говорю об автоматически сгенерированном servicePointNumber, я имею в виду, если я добавлю новый ServicePoint (поставщик), чем для идентификатора поставщика, например. 5 я получаю следующее, например, точка 3 -> (5,3), но это не просто автоматически увеличивается, поэтому (5,3), (4,3), (1,3) = (providerId, servicePointNo) будет позволил 09.06.2015
  • Я предпочитаю использовать @EmbeddedID, так как это уменьшает дублирование всех атрибутов в двух классах и вероятность их рассинхронизации. Я всегда думал, что @IdClass в спецификации соответствует методу, используемому в спецификации Container Managed Persistence до JPA. 09.06.2015
  • Отредактированный ответ, чтобы добавить предложение для ОБНОВЛЕНИЯ 2 09.06.2015
  • хорошо, спасибо, на самом деле я тоже делаю это сам, основываясь на этой справочной спецификации JPA 2.1, раздел 2.4.1.3, которую вы рекомендовали :) 09.06.2015

  • 2

    Лучший способ сделать составные первичные ключи — использовать @EmbeddedId с соответствующим классом @Embeddable.

    Из наших 400 с лишним сущностей базы данных около 135 использовали классы Embedded ID для реализации составных (многополевых) первичных ключей.

    Здесь на SO много вопросов и ответов с примерами.

    09.06.2015
  • Есть ли принципиальная разница в использовании .@EmbeddedId вместо .@IdClass ? 09.06.2015
  • @Michael См. этот вопрос и этот вопрос здесь, в SO, для обсуждения разницы. Наш наставник из SUN Microsystems научил нас этому @EmbeddedId пути еще в 2006 году, когда мы впервые начали работать над EJB3. Я считаю, что @EmbeddedId - это более новый, более объектно-ориентированный способ создания составных ключей. 09.06.2015
  • Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

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

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..