У меня есть класс Client и Affiliate, унаследованный от класса Person. Используется тип стратегии присоединенного наследования - каждая из них имеет общий первичный ключ с родительским классом. Поскольку столбца дискриминатора нет, мы решили использовать DescriptorCustomizer . Но на самом деле это не дает никакого представления о том, как это работает, а также код, похоже, не компилируется. Было бы неплохо, если бы кто-нибудь для понимания привел хороший пример с фрагментом кода.

3
Viju Nil 14 Мар 2014 в 23:12
«код не компилируется» Не лучше было бы вставить ваш код, чтобы мы могли его изучить и попытаться найти первопричину?
 – 
wypieprz
15 Мар 2014 в 00:08
Код, представленный на веб-сайте EclipseLink, не компилируется. В AirMilesExtractor extractorClassFromRow() имеет тип возвращаемого значения void, и даже тогда он возвращает Class. Кроме того, непонятно, чего он пытается достичь.
 – 
Viju Nil
15 Мар 2014 в 07:51

1 ответ

Лучший ответ

Согласно упомянутой документации:

Если вы выполняете сопоставление с существующей базой данных, а в таблицах нет столбец дискриминатора, вы все равно можете определить наследование, используя Аннотация @ClassExtractor или элемент <class-extractor>. Класс экстрактор принимает класс, реализующий ClassExtractor интерфейс. Экземпляр этого класса используется для определения класса тип для использования в строке базы данных. Средство извлечения классов должно определять extractClassFromRow() метод, который принимает базу данных Record и Session.

Нам нужно аннотировать корневую сущность в иерархии, определяемой пользователем с помощью экстрактора классов:

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@ClassExtractor(PersonClassExtractor.class)
public abstract class Person {
    @Id @GeneratedValue(strategy = GenerationType.AUTO)
    private int id;
    private String name;
    private int age;
    // ...
}

Обратите внимание, что мы не используем аннотации @Customizer, поскольку это не требуется в случае стратегии наследования JOINED:

Если экстрактор классов используется с наследованием SINGLE_TABLE, строки типа класса должны иметь возможность фильтрации в запросах. Это может быть достигается установкой onlyInstancesExpression() или withAllSubclassesExpression() для классов ответвления. Их можно установить к Expression объектам с помощью DescriptorCustomizer.

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

  • имя столбца, уникальное для данного типа сущности среди других
  • критерии, основанные на значениях данного столбца корневой сущности

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

@Entity
public class Client extends Person {
    @Column(name = "CLIENT_SPECIFIC")
    private String clientSpecific;
    // ...
}

@Entity
public class Affiliate extends Person {
    @Column(name = "AFFILIATE_SPECIFIC")
    private float affiliateSpecific;
    // ...
}

Тогда экстрактор классов может выглядеть следующим образом:

public class PersonClassExtractor extends ClassExtractor {
    @Override
    public Class<?> extractClassFromRow(Record databaseRow, Session session) {
        if (databaseRow.containsKey("CLIENT_SPECIFIC")) {
            return Client.class;
        } else if (databaseRow.containsKey("AFFILIATE_SPECIFIC")) {
            return Affiliate.class;
        } else {
            return Person.class; // this should never happen
        }
    }
}

  • получить список клиентов и партнеров
List<Person> polymorphicResults = em.createQuery("SELECT p FROM Person p")
                                    .getResultList();
  • получить список аффилированных лиц или клиентов соответственно
List<Affiliate> concreteResults = em.createQuery("SELECT a FROM Affiliate a")
                                    .getResultList();

List<Client> concreteResults = em.createQuery("SELECT c FROM Client c")
                                 .getResultList();
6
wypieprz 16 Мар 2014 в 03:06