Spring JPA ManyToOne не создает экземпляры для детей - PullRequest
0 голосов
/ 07 марта 2019

Удивительно, но я дошел до этого момента в жизни, не имея отношений между родителем и ребенком. Я не буду останавливаться на том, как много примеров я посмотрел, кроме как сказать, что я смотрел на MANY . Этот парень кажется одним из лучших. Единственная проблема в том, что каждый пример, который я могу найти, является либо «сокращенным» (только те части, которые, по мнению автора, были интересны, либо настолько старые, что они вообще не компилируются, либо не используют JPA и т. Д. И т. Д.

Мой очень простой случай - у меня есть объект, представляющий конечную точку отдыха. В дочерней таблице будет строка для каждого http-заголовка, необходимого для вызова. (Конечно, это еще не все, но это самый простой пример).

Целевая среда - это текущие версии всего, например. Пружинный ботинок 2.1.3. Релиз и т. Д.

После долгих раздумий я создал строки БД, хотя "Я" думаю, что должен быть лучший способ. Однако я не могу найти находку для создания экземпляра дочерней коллекции.

МОДЕЛЬ РОДИТЕЛЯ (некоторые столбцы удалены только для того, чтобы сделать сообщение короче)

@Entity
@Table(name = "EXT_PROVIDER")
public class ExtProvider extends AuditModel {
private String serviceName;
private String serviceType;



@Id
@Column(name = "SERVICE_NAME", nullable = false, length = 30)
public String getServiceName() {
    return serviceName;
}

public void setServiceName(String serviceName) {
    this.serviceName = serviceName;
}

@Basic
@Column(name = "SERVICE_TYPE", nullable = false, length = 50)
public String getServiceType() {
    return serviceType;
}

public void setServiceType(String serviceType) {
    this.serviceType = serviceType;
}


@OneToMany(mappedBy = "extProvider", cascade = CascadeType.ALL, orphanRemoval = true)
public List<ExtProviderHeader> headers = new ArrayList<>();

public void addExtProviderHeader(ExtProviderHeader header) {
    headers.add(header);
    header.setExtProvider(this);
}

public void removeExtProviderHeader(ExtProviderHeader header) {
    headers.remove(header);
    header.setExtProvider(null);
}

public void setExtProviderHeader(List<ExtProviderHeader> headers) {
    this.headers = headers;
}

public void setHeaders(List<ExtProviderHeader> headers) {
    this.headers = headers;
}

Если это некомментированный, спящий режим перестает работать с hibernate.MappingException: не удалось определить тип для: java.util.List, для таблицы: ext_provider, для столбцов: [org.hibernate.mapping.Column (headers)]

Но если вы не можете сделать это, как @Service должен получать данные, даже если они загружаются

//public List<ExtProviderHeader> getHeaders() {
//  return headers;
//}

МОДЕЛЬ РЕБЕНКА

@Entity
@Table(name = "EXT_PROVIDER_HEADER")
public class ExtProviderHeader {

@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "extProviderSeq")
@SequenceGenerator(name = "extProviderSeq", sequenceName = "EXT_PROVIDER_SEQ", allocationSize = 5)
@Column(name = "DATA_ID", nullable = false, precision = 0)
private Long dataId;
public Long getDataId() {
    return dataId;
}

public void setDataId(Long dataId) {
    this.dataId = dataId;
}

@Basic
@Column(name = "HEADER_KEY", nullable = false, length = 30)
private String headerKey;
public String getHeaderKey() {
    return headerKey;
}

public void setHeaderKey(String headerKey) {
    this.headerKey = headerKey;
}

@Basic
@Column(name = "HEADER_VALUE", nullable = false, length = 50)
private String headerValue;
public String getHeaderValue() {
    return headerValue;
}

public void setHeaderValue(String headerValue) {
    this.headerValue = headerValue;
}

@Basic
@Column(name = "SERVICE_NAME", nullable = false, length = 30, insertable = true, updatable = true)
private String serviceName;
public String getServiceName() { return serviceName; }

public void setServiceName(String serviceName) { this.serviceName = serviceName; }


@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "SERVICE_NAME", insertable = false, updatable = false)
private ExtProvider extProvider;

public ExtProvider getExtProvider() { return extProvider; }

public void setExtProvider(ExtProvider extProvider) { this.extProvider = extProvider; }

репозитории

@Repository
public interface ExtProviderRepository extends JpaRepository<ExtProvider, String> {

}
@Repository
public interface ExtProviderHeaderRepository extends JpaRepository<ExtProviderHeader, Long> {

    ExtProviderHeader findByDataId(Long primaryKey);
}

JUNIT для создания строк

Я думаю, что нет никакого способа обойти множественные сохранения, потому что первичный ключ для дочерних строк - это SEQUENCE, и существует отношение FOREIGN KEY к Parent. Так что, хотя мне это не нравится, кажется, застряло.

Приветствуются разные советы

@Test
@DisplayName("Save Provder and Headers")
public void saveProvider() {

    ExtProvider extProvider = new ExtProvider();
    extProvider.setServiceName("MS6");
    extProvider.setServiceType("MESSAGING");
    extProvider = extProviderRepository.save(extProvider);

    ExtProviderHeader extProviderHeader = new ExtProviderHeader();
    extProviderHeader.setHeaderKey("Authorization: OAuth");
    extProviderHeader.setHeaderValue("xxxx-xxxxxxxx");
    extProviderHeader.setServiceName(extProvider.getServiceName());
    extProviderHeader = extProviderHeaderRepository.save(extProviderHeader);

    extProvider.addExtProviderHeader(extProviderHeader);

    extProviderHeader = new ExtProviderHeader();  
    extProviderHeader.setHeaderKey("Content-Type");
    extProviderHeader.setHeaderValue("application/json");
    extProviderHeader.setServiceName(extProvider.getServiceName());
    extProviderHeader = extProviderHeaderRepository.save(extProviderHeader);


    extProvider.addExtProviderHeader(extProviderHeader);

    ExtProvider save = extProviderRepository.save(extProvider);

    logger.info("Provider Ceated");
    }

JUNIT для создания экземпляра объекта обратно в память

Здесь коллекция headers возвращается пустой.

@Test
public void createProvider() {

    Optional<ExtProvider> optional = extProviderRepository.findById("MS6");
    ExtProvider extProvider = optional.get();

    logger.info("PROVIDER:{}", extProvider);
    List<ExtProviderHeader> headers = extProvider.headers;
    for(ExtProviderHeader header : headers) {
        logger.info("Header is:{}", header);
    }

Замечания:

  1. Очевидно, что отсутствие получателя заголовков нарушает ОО. Но если я раскомментирую, то getter hibernate не сможет инициализироваться. Я здесь упускаю важный момент.
  2. В некоторых примерах говорится, что LIST заменяется на SET или даже COLLECTION. Это не имеет никакого значения.
  3. В большинстве примеров НЕ имеется Модель, которая фактически создает экземпляр коллекции. Хотя ссылка, которую я указал в верхней части поста, есть. Этот парень является основным участником проекта hibernate, поэтому я хочу доверять ему. Это было бы проще, если бы его код работал!
  4. Независимо от того, если Модель не выделяет ArrayList, тогда JUNIT получает NPE, когда он пытается перебрать коллекцию. Конечно, все это действительно говорит нам о том, что Hibernate даже не пытался установить эту коллекцию. Я ожидаю, что Hibernate установит пустой список, если это вообще сработает.

РЕДАКТИРОВАТЬ: Я обнаружил, что я могу получить заголовки, сделав этот вызов:

extProvider.setHeaders(extProviderHeaderRepository.findByExtProvider(extProvider));

Это немного круто, наверное. Я ожидал, что, когда я "сделаю ссылку" на спящий сборник, он будет заполнен - ​​вот как я читаю FetchType.LAZY должен работать. Конечно, переход на FetchType.Eager ничего другого не делал.

Я также выяснил, если я не использую «get» в названии метода, т.е. изменим getHeaders на headersList Hibernate прекратит попытки сопоставить коллекцию с базой данных колонка.

Так что со всем этим он работает более или менее. Но это все полностью вручную. Я не вижу реального преимущества в том, чтобы иметь их как отдельные объекты и вручную управлять ими.

Может быть, я все еще что-то упускаю. ИЛИ может быть, это всего лишь одна абстракция, слишком далеко, чтобы действительно работать так, как рекламируется. Я буду продолжать тыкать в это.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...