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

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

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

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

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

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

@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 не должен быть null. Мне это нужно, чтобы избежать создания 200 репозиториев для доступа ко всему списку возможных значений для каждого типа ALNDOMAIN.

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

2 ответа

  1. Ваши сущности имеют два сопоставления со столбцом «ALNNAME» —

    1. Тип класса, как указано с @DiscriminatorColumn и
      @ DiscriminatorValue аннотации.

    2. Свойство alnname помечено только для чтения через параметры столбца@.

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

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

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

    В основном Я заменил свой метод:
    Список Findbyalnname (@Param («alnname») строка 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();
            }