Спящий режим: дополнительная аннотация к столбцу из наследства

у меня есть класс

@MappedSuperclass
public abstract class MyAbstractProperty <T extends Object>{

    @Id
    @GeneratedValue(strategy = GenerationType.TABLE)
    private Long id;

    @Column(name="defaultValue")
    protected T defaultValue;

//...

}

Что является основой для подклассов, таких как class MyLongProperty extends MyAbstractProperty<Long>{}. Это прекрасно работает. Проблема возникает, когда я хочу сохранить текст в классе class MyStringProperty extends MyAbstractProperty<String>{}.

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

@Entity
class MyStringProperty extends MyAbstractProperty<String>{

    @Type(type="org.hibernate.type.StringClobType")
    @Column(name="defaultValue")
    protected String defaultValue; // problem since defaultValue is already defined in MyAbstractProperty<>.
}

Как я могу обеспечить это, поскольку значение по умолчанию уже определено в MyAbstractProperty? Я не думаю, что можно переместить аннотацию типа на MyAbstractProperty, так как это может иметь побочные эффекты для других классов, таких как MyLongProperty.

Например, когда я устанавливал @Lob в MyAbstractProperty, определение SQL MyStringProperty включало DEFAULTVALUE BLOB(255) вместо DEFAULTVALUE BIGINT.

Дополнительный вопрос: похоже, существуют разные варианты определения столбца как текстовых данных (например, @Type(type="org.hibernate.type.StringClobType"), @Lob). В чем основные различия этих параметров. Что лучше взять. (Моя основная база данных — HyperSQL, но я также ориентируюсь на SQLite, MariaDB и MySQL).

Изменить

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

У меня была альтернативная - незаконченная - идея, которая могла бы вызвать меньше модификаций моего кода. Можно ли определить класс

class MyText extendes String; 

например, все экземпляры MyText автоматически сохраняются как @Lob? Тогда мне просто нужно изменить MyAbstractProperty<String> на MyAbstractProperty<MyText>.


person BerndGit    schedule 27.02.2017    source источник
comment
я думаю, вам нужно следовать одной из стратегий наследования, поэтому, пожалуйста, прочитайте эту статью thejavageek.com/2014/05/14/jpa-single-table-inheritance-example   -  person mibrahim.iti    schedule 28.02.2017
comment
Поэтому в основном вам нужно использовать аннотацию @Inheritance со стратегией, которую вы хотите использовать в своем абстрактном классе.   -  person mibrahim.iti    schedule 28.02.2017
comment
Также я думаю, что вы должны удалить defaultValue из MyStringProperty, так как он уже будет в суперклассе, и переместить @Type(type=org.hibernate.type.StringClobType) в MyAbstractProperty   -  person mibrahim.iti    schedule 28.02.2017
comment
И последнее, если вы используете JPA с провайдером Hibernate, почему вы просто не используете аннотацию @lob в своей строке? пожалуйста, взгляните на docs.oracle.com/javaee/5 /api/javax/persistence/Lob.html   -  person mibrahim.iti    schedule 28.02.2017
comment
@mibrahim.iti: перемещение аннотации в MyAbstractProperty может иметь побочные эффекты для таких классов, как MyLongProperty. Я думаю, что где-то видел возможность изменить спецификацию столбцов, которые были определены в суперклассах, но я не нашел этого в документации по спящему режиму.   -  person BerndGit    schedule 28.02.2017
comment
@Lob также является возможностью, которую я хочу исследовать. Однако здесь у меня такая же трудность с размещением его в правильном классе.   -  person BerndGit    schedule 28.02.2017
comment
Я не думаю, что вы можете иметь @Column для общей (T) переменной. У Hibernate не было бы возможности узнать, как отобразить это. Кроме того, поскольку у каждой переменной есть один столбец, у вас не может быть столбца, который может содержать, например, как строку, так и целое число.   -  person Tobb    schedule 01.03.2017
comment
Я бы удалил переменную из абстрактного класса и заменил ее абстрактным методом get (чтобы указать наследующим классам, что им нужно определить это значение, сопоставленное с некоторым столбцом)   -  person Tobb    schedule 01.03.2017
comment
@Tobb: в основном здесь работает аннотация столбца, поскольку абстрактный класс не имеет сущности. Протестировано для длинных, логических и строковых значений (с ограничением в 255 символов).   -  person BerndGit    schedule 01.03.2017
comment
@Tobb: я буду больше изучать подход getter/setter.   -  person BerndGit    schedule 01.03.2017
comment
А, это сопоставленный суперкласс. Тогда вы сможете переопределить переменную в подклассе и добавить @Lob для более длинной строки..   -  person Tobb    schedule 01.03.2017
comment
Ok. Я был удивлен, увидев, что могу сделать это без ошибки компиляции (просто предупреждение: поле скрывает другое поле). Однако теперь у меня есть исключение во время выполнения, которое я должен исследовать более подробно. Возможно, доступ к данным, который использует суперкласс, теперь не использует правильное поле.   -  person BerndGit    schedule 01.03.2017
comment
Кажется, что методы из «MyAbstractProperty» все еще используют переменную без @Lob. Я могу попытаться повторно реализовать определенные методы в MyStringProperty, но это похоже на антипаттерн. У меня есть опасения по поводу надежности этого подхода.   -  person BerndGit    schedule 01.03.2017
comment
@BerndGit я думаю, что нет способа переопределить свойство defaultValue, единственный способ - удалить его из универсального класса и поместить его непосредственно в каждый подкласс, поэтому в вашем универсальном классе будет только идентификатор.   -  person mibrahim.iti    schedule 02.03.2017


Ответы (1)


Вы можете оставить только абстрактный геттер в суперклассе и определить поле в подклассах:

@MappedSuperclass
public abstract class MyAbstractProperty<T extends Object>{

    @Id
    @GeneratedValue(strategy = GenerationType.TABLE)
    private Long id;

    public abstract T getDefaultValue();
}

@Entity
class MyStringProperty extends MyAbstractProperty<String>{

    @Type(type="org.hibernate.type.StringClobType")
    @Column(name="defaultValue")
    protected String defaultValue;

    @Override
    public String getDefaultValue() {
        return defaultValue;
    }
}

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

@MappedSuperclass
public abstract class MyDefaultProperty<T> extends MyAbstractProperty<T extends Object> {

    @Column(name="defaultValue")
    protected T defaultValue;

    @Override
    public T getDefaultValue() {
        return defaultValue;
    }
}
person Dragan Bozanovic    schedule 02.03.2017
comment
Спасибо, Драган Бозанович, за ваш ответ. Это кажется возможным, хотя потребуется некоторый рефакторинг моего кода. Пожалуйста, проверьте также редактирование моего вопроса. Может быть, эта идея может привести к более простому решению? - person BerndGit; 03.03.2017
comment
@BerndGit Вы не можете расшириться от String, это последний класс. И даже если бы вы могли, эффект был бы таким же, так как вам нужно было бы разместить аннотацию @Lob на поле типа MyText в содержащем классе. - person Dragan Bozanovic; 03.03.2017