Столбец дискриминатора Eclipselink возвращает NULL

Этот вопрос касается JPA и дискриминаторов.

Мотивация: я реализую систему с различными полями, для которых потребуются некоторые значения домена. Например, типы для полей (тип пола: мужской и женский; тип удостоверения личности: водительские права; тип авеню и т. д.).

Поскольку моя система управляется метаданными, я не буду создавать эти атрибуты как ENUM. Мне нужно, чтобы они были в легкодоступном месте.

Для этого я создал родительский абстрактный класс ALNDOMAIN (буквенно-цифровые домены). И все унаследованные классы будут частью моих объектов (например, IDType расширяет ALNDomain).

Проблема: в моей системе будет около 200 подклассов ALNDomains. Я не хочу создавать один репозиторий для каждого подкласса. Я бы предпочел иметь один репозиторий в классе ALNDomain и получать значение дискриминатора. Каждый раз, когда я извлекаю свой домен, столбцы дискриминатора становятся нулевыми:

@Entity
@DiscriminatorColumn(name="ALNNAME", discriminatorType = DiscriminatorType.STRING)
public abstract class ALNDomain {

	@Id
	@GeneratedValue(strategy=GenerationType.IDENTITY)
	private Long id;
	
	@Column(name="ALNNAME", insertable = false, updatable = false, nullable = false)
	private String alnname;
	private String value;
	private String description;
	
	public long getId() {
		return id;
	}
	public void setId(long id) {
		this.id = id;
	}
	public String getValue() {
		return value;
	}
	public void setValue(String value) {
		this.value = value;
	}
	public String getDescription() {
		return description;
	}
	public void setDescription(String description) {
		this.description = description;
	}
	public String getAlnname() {
		return alnname;
	}
	public void setAlnname(String alnname) {
		this.alnname = alnname;
	}
}

Это подкласс:

package com.ang.entity.core;

import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;

import com.ang.entity.base.domains.ALNDomain;

@Entity
@DiscriminatorValue("IDTYPE")
public class IDType extends ALNDomain {

}

Это мой репозиторий:

@RepositoryRestResource(collectionResourceRel = "alndomain", path = "alndomain")
@CrossOrigin(maxAge = 3600)
public interface ALNDomainRepository extends PagingAndSortingRepository<ALNDomain, Long>{
	List<ALNDomain> findByAlnname(@Param("alnname") String alnname);
}

Когда я обращаюсь к моему репозиторию, столбец дискриминатора имеет значение null. Вот результат:

{
  "_embedded" : {
    "iDTypes" : [ {
      **"alnname" : null,**
      "value" : "RG",
      "description" : "Registro Nacional",
      "_links" : {
        "self" : {
          "href" : "http://localhost:8080/iDType/1"
        },
        "iDType" : {
          "href" : "http://localhost:8080/iDType/1"
        }
      }
    } ]
  },

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

Спасибо за внимание.


person Alisson Godoi    schedule 07.11.2016    source источник
comment
Как вы вставляете подкласс и каково значение alnname при вызове persist? Если оно не установлено при вызове persist, оно не будет установлено при следующем доступе к нему, если только вы не принудительно перезагрузите/обновите свойство из базы данных. Кэширование сохранит этот экземпляр в памяти.   -  person Chris    schedule 07.11.2016
comment
Привет, Крис, я не устанавливаю ALNName, так как это столбец, который должен автоматически заполняться значением дискриминатора: @DiscriminatorValue(IDTYPE) Должен ли я вручную устанавливать ALNName? Или он должен автоматически устанавливаться? Также обратите внимание, что я следую рекомендации установить ALNName как insertable = false, updateable = false, поскольку им должен управлять JPA, а не вручную.   -  person Alisson Godoi    schedule 09.11.2016


Ответы (2)


У ваших объектов есть два сопоставления со столбцом «ALNNAME»:

  1. Тип класса, указанный в аннотациях @DiscriminatorColumn и @DiscriminatorValue.

  2. Свойство alnname помечено как доступное только для чтения в настройках @Column.

Эти два сопоставления полностью независимы друг от друга и не связаны в JPA. Таким образом, хотя alnname будет установлено, если объект загружается из базы данных, JPA никогда не будет устанавливать его до тех пор.

Это свойство в значительной степени полностью избыточно, хотя JPA поддерживает функцию TYPE в запросах, а экземпляры Java могут получать имя класса. Если вы должны сохранить это свойство в своей сущности, вам лучше установить его при создании нового экземпляра подкласса или вместо этого переопределить метод get для подклассов, чтобы вместо этого возвращать желаемую строку. Невозможно изменить значение экземпляра - java не позволяет вам преобразовывать объект из одного класса в другой, поэтому в JPA это невозможно без создания совершенно нового экземпляра.

person Chris    schedule 09.11.2016
comment
Хорошо, Крис, спасибо за ценный отзыв. Основываясь на этом, я нашел альтернативный способ динамического создания экземпляра репозитория Spring. В основном я делаю новый SimpleJpaRepository‹ALNDomain, Long›(domainClass,em), где domainClass — это динамический класс, загружаемый на основе моей метамодели. - person Alisson Godoi; 10.11.2016

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

В основном я заменил свой метод: List findByAlnname(@Param("alnname") String domainClassName)

выполнить следующее:

        Class domainClass;
        try {
            domainClass = ClassLoader.getSystemClassLoader().loadClass(domainClassName);
            if (domainClass!=null && ALNDomain.class.isAssignableFrom(domainClass)) {

                SimpleJpaRepository<ALNDomain, Long> jpaRep = new SimpleJpaRepository<ALNDomain, Long>(domainClass,em);

                return jpaRep.findAll();
            }   
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
person Alisson Godoi    schedule 09.11.2016