Можно ли установить значение по умолчанию для столбцов в JPA, и если, то как это делается с помощью аннотаций?
Установка значений по умолчанию для столбцов в JPA
Ответы (17)
На самом деле это возможно в JPA, хотя это небольшая хитрость с использованием свойства columnDefinition аннотации @Column, например:
@Column(name="Price", columnDefinition="Decimal(10,2) default '100.00'")
50.22 выдает ошибку усечения данных в определении DECIMAL(2,2) столбца. +1
- person qualebs; 18.03.2014
insertable=false, если столбец допускает значение NULL (и чтобы избежать ненужного аргумента столбца).
- person eckes; 07.08.2015
javax.persistence пакеты) представляет собой перекрестную реализацию JPA и перекрестную реализацию диалекта SQL / СУБД. Не все могут понять, например, DEFAULT CURRENT_TIMESTAMP. columnDefinition может быть устаревшим в пользу упомянутых выше взаимозависимостей.
- person Roland; 14.10.2017
Вы можете сделать следующее:
@Column(name="price")
private double price = 0.0;
Там! Вы только что использовали ноль в качестве значения по умолчанию.
Обратите внимание, что это будет полезно, если вы обращаетесь к базе данных только из этого приложения. Если другие приложения также используют базу данных, вам следует выполнить эту проверку из базы данных, используя атрибут аннотации Кэмерона columnDefinition или каким-либо другим способом.
Example в качестве прототипа для поиска. После установки значения по умолчанию пример запроса Hibernate больше не будет игнорировать связанный столбец, тогда как раньше он игнорировал его, потому что он был пустым. Лучше всего установить все значения по умолчанию непосредственно перед вызовом Hibernate save() или update(). Это лучше имитирует поведение базы данных, которая устанавливает значения по умолчанию при сохранении строки.
- person Derek Mahar; 03.08.2010
null). Использование @PrePersist и @PreUpdate - лучший вариант imho.
- person Jasper; 05.10.2011
@PrePersist. Тем не менее, оба способа хороши, ИМО.
- person Piotr Nowicki; 08.06.2012
columnDefinition не зависит от базы данных и @PrePersist переопределяет ваш параметр перед вставкой, значение по умолчанию - другое, значение по умолчанию используется, когда значение не установлено явно.
- person Utku Özdemir; 26.02.2014
другой подход - использование javax.persistence.PrePersist
@PrePersist
void preInsert() {
if (this.createdTime == null)
this.createdTime = new Date();
}
if (createdt != null) createdt = new Date(); или что-то в этом роде? Прямо сейчас это переопределит явно указанное значение, что, похоже, не делает его значением по умолчанию.
- person Max Nanasy; 26.11.2014
if (createdt == null) createdt = new Date();
- person Shane; 16.12.2014
null.
- person Ondra Žižka; 02.10.2017
В 2017 году в JPA 2.1 по-прежнему есть только @Column(columnDefinition='...'), в который вы помещаете буквальное определение столбца SQL. Это довольно негибко и вынуждает вас также объявлять другие аспекты, такие как тип, сокращая точку зрения реализации JPA по этому вопросу.
Однако в Hibernate есть следующее:
@Column(length = 4096, nullable = false)
@org.hibernate.annotations.ColumnDefault("")
private String description;
Определяет значение DEFAULT для применения к связанному столбцу через DDL.
- Hibernate 4.3 docs (4.3, чтобы показать он здесь довольно давно)
- Руководство Hibernate по значение по умолчанию для столбца базы данных
Два примечания к этому:
1) Не бойтесь нестандартных решений. Работая разработчиком JBoss, я видел довольно много процессов спецификации. Спецификация - это, по сути, базовый уровень, который крупные игроки в данной области готовы поддержать в течение следующего десятилетия или около того. Это верно для безопасности, для обмена сообщениями ORM не имеет значения (хотя JPA охватывает довольно много). Мой опыт как разработчика показывает, что в сложном приложении рано или поздно вам все равно понадобится нестандартный API. И @ColumnDefault - пример, когда он перевешивает недостатки использования нестандартного решения.
2) Приятно, как все машут @PrePersist или инициализацией члена конструктора. Но это НЕ то же самое. Как насчет массовых обновлений SQL? Как насчет утверждений, которые не устанавливают столбец? DEFAULT выполняет свою роль, и ее нельзя заменить инициализацией члена класса Java.
JPA не поддерживает это, и было бы полезно, если бы это было так. Использование columnDefinition зависит от БД и во многих случаях неприемлемо. установки значения по умолчанию в классе недостаточно, когда вы извлекаете запись, имеющую нулевые значения (что обычно происходит при повторном запуске старых тестов DBUnit). Что я делаю, так это:
public class MyObject
{
int attrib = 0;
/** Default is 0 */
@Column ( nullable = true )
public int getAttrib()
/** Falls to default = 0 when null */
public void setAttrib ( Integer attrib ) {
this.attrib = attrib == null ? 0 : attrib;
}
}
В этом очень помогает автоматическая упаковка Java.
Видя, как я наткнулся на это в Google, пытаясь решить ту же проблему, я просто добавлю решение, которое я приготовил, на случай, если кто-то сочтет его полезным.
На мой взгляд, реально существует только одно решение этой проблемы - @PrePersist. Если вы сделаете это в @PrePersist, вы должны проверить, установлено ли уже значение.
@PrePersist для использования OP. @Column(columnDefinition=...) не кажется очень элегантным.
- person Piotr Nowicki; 08.06.2012
@Column(columnDefinition="tinyint(1) default 1")
Я только что проверил проблему. Работает отлично. Спасибо за подсказку.
О комментариях:
@Column(name="price")
private double price = 0.0;
Этот не устанавливает значение столбца по умолчанию в базе данных (конечно).
вы можете использовать java Reflect api:
@PrePersist
void preInsert() {
PrePersistUtil.pre(this);
}
Это обычное дело:
public class PrePersistUtil {
private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
public static void pre(Object object){
try {
Field[] fields = object.getClass().getDeclaredFields();
for(Field field : fields){
field.setAccessible(true);
if (field.getType().getName().equals("java.lang.Long")
&& field.get(object) == null){
field.set(object,0L);
}else if (field.getType().getName().equals("java.lang.String")
&& field.get(object) == null){
field.set(object,"");
}else if (field.getType().getName().equals("java.util.Date")
&& field.get(object) == null){
field.set(object,sdf.parse("1900-01-01"));
}else if (field.getType().getName().equals("java.lang.Double")
&& field.get(object) == null){
field.set(object,0.0d);
}else if (field.getType().getName().equals("java.lang.Integer")
&& field.get(object) == null){
field.set(object,0);
}else if (field.getType().getName().equals("java.lang.Float")
&& field.get(object) == null){
field.set(object,0.0f);
}
}
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ParseException e) {
e.printStackTrace();
}
}
}
Field[] fields = object.getClass().getDeclaredFields(); в for(). А также добавьте final в свой параметр / перехваченные исключения, так как вы не хотите, чтобы object было случайно изменено. Также добавьте чек на null: if (null == object) { throw new NullPointerException("Parameter 'object' is null"); }. Это гарантирует, что object.getClass() безопасно вызывать и не вызывает NPE. Причина в том, чтобы избежать ошибок ленивых программистов. ;-)
- person Roland; 02.11.2017
Я использую columnDefinition, и он очень хорошо работает
@Column(columnDefinition="TIMESTAMP DEFAULT CURRENT_TIMESTAMP")
private Date createdDate;
Вы не можете сделать это с аннотацией столбца. Я думаю, что единственный способ - установить значение по умолчанию при создании объекта. Возможно, конструктор по умолчанию будет подходящим местом для этого.
@Column нет общей аннотации или атрибута. И еще мне не хватает комментариев (взятых из документа Java).
- person Roland; 14.10.2017
В моем случае я модифицировал исходный код hibernate-core, ну, чтобы ввести новую аннотацию @DefaultValue:
commit 34199cba96b6b1dc42d0d19c066bd4d119b553d5
Author: Lenik <xjl at 99jsj.com>
Date: Wed Dec 21 13:28:33 2011 +0800
Add default-value ddl support with annotation @DefaultValue.
diff --git a/hibernate-core/src/main/java/org/hibernate/annotations/DefaultValue.java b/hibernate-core/src/main/java/org/hibernate/annotations/DefaultValue.java
new file mode 100644
index 0000000..b3e605e
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/annotations/DefaultValue.java
@@ -0,0 +1,35 @@
+package org.hibernate.annotations;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Retention;
+
+/**
+ * Specify a default value for the column.
+ *
+ * This is used to generate the auto DDL.
+ *
+ * WARNING: This is not part of JPA 2.0 specification.
+ *
+ * @author 谢继雷
+ */
[email protected]({ FIELD, METHOD })
+@Retention(RUNTIME)
+public @interface DefaultValue {
+
+ /**
+ * The default value sql fragment.
+ *
+ * For string values, you need to quote the value like 'foo'.
+ *
+ * Because different database implementation may use different
+ * quoting format, so this is not portable. But for simple values
+ * like number and strings, this is generally enough for use.
+ */
+ String value();
+
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/Ejb3Column.java b/hibernate-core/src/main/java/org/hibernate/cfg/Ejb3Column.java
index b289b1e..ac57f1a 100644
--- a/hibernate-core/src/main/java/org/hibernate/cfg/Ejb3Column.java
+++ b/hibernate-core/src/main/java/org/hibernate/cfg/Ejb3Column.java
@@ -29,6 +29,7 @@ import org.hibernate.AnnotationException;
import org.hibernate.AssertionFailure;
import org.hibernate.annotations.ColumnTransformer;
import org.hibernate.annotations.ColumnTransformers;
+import org.hibernate.annotations.DefaultValue;
import org.hibernate.annotations.common.reflection.XProperty;
import org.hibernate.cfg.annotations.Nullability;
import org.hibernate.mapping.Column;
@@ -65,6 +66,7 @@ public class Ejb3Column {
private String propertyName;
private boolean unique;
private boolean nullable = true;
+ private String defaultValue;
private String formulaString;
private Formula formula;
private Table table;
@@ -175,7 +177,15 @@ public class Ejb3Column {
return mappingColumn.isNullable();
}
- public Ejb3Column() {
+ public String getDefaultValue() {
+ return defaultValue;
+ }
+
+ public void setDefaultValue(String defaultValue) {
+ this.defaultValue = defaultValue;
+ }
+
+ public Ejb3Column() {
}
public void bind() {
@@ -186,7 +196,7 @@ public class Ejb3Column {
}
else {
initMappingColumn(
- logicalColumnName, propertyName, length, precision, scale, nullable, sqlType, unique, true
+ logicalColumnName, propertyName, length, precision, scale, nullable, sqlType, unique, defaultValue, true
);
log.debug( "Binding column: " + toString());
}
@@ -201,6 +211,7 @@ public class Ejb3Column {
boolean nullable,
String sqlType,
boolean unique,
+ String defaultValue,
boolean applyNamingStrategy) {
if ( StringHelper.isNotEmpty( formulaString ) ) {
this.formula = new Formula();
@@ -217,6 +228,7 @@ public class Ejb3Column {
this.mappingColumn.setNullable( nullable );
this.mappingColumn.setSqlType( sqlType );
this.mappingColumn.setUnique( unique );
+ this.mappingColumn.setDefaultValue(defaultValue);
if(writeExpression != null && !writeExpression.matches("[^?]*\\?[^?]*")) {
throw new AnnotationException(
@@ -454,6 +466,11 @@ public class Ejb3Column {
else {
column.setLogicalColumnName( columnName );
}
+ DefaultValue _defaultValue = inferredData.getProperty().getAnnotation(DefaultValue.class);
+ if (_defaultValue != null) {
+ String defaultValue = _defaultValue.value();
+ column.setDefaultValue(defaultValue);
+ }
column.setPropertyName(
BinderHelper.getRelativePath( propertyHolder, inferredData.getPropertyName() )
diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/Ejb3JoinColumn.java b/hibernate-core/src/main/java/org/hibernate/cfg/Ejb3JoinColumn.java
index e57636a..3d871f7 100644
--- a/hibernate-core/src/main/java/org/hibernate/cfg/Ejb3JoinColumn.java
+++ b/hibernate-core/src/main/java/org/hibernate/cfg/Ejb3JoinColumn.java
@@ -423,6 +424,7 @@ public class Ejb3JoinColumn extends Ejb3Column {
getMappingColumn() != null ? getMappingColumn().isNullable() : false,
referencedColumn.getSqlType(),
getMappingColumn() != null ? getMappingColumn().isUnique() : false,
+ null, // default-value
false
);
linkWithValue( value );
@@ -502,6 +504,7 @@ public class Ejb3JoinColumn extends Ejb3Column {
getMappingColumn().isNullable(),
column.getSqlType(),
getMappingColumn().isUnique(),
+ null, // default-value
false //We do copy no strategy here
);
linkWithValue( value );
Что ж, это решение только для гибернации.
@Column(columnDefinition='...')не работает, если вы устанавливаете ограничение по умолчанию в базе данных при вставке данных.- Вам нужно сделать
insertable = falseи удалитьcolumnDefinition='...'из аннотации, тогда база данных автоматически вставит значение по умолчанию из базы данных. - Например. когда вы устанавливаете пол varchar по умолчанию в базе данных мужской.
- Вам просто нужно добавить
insertable = falseв Hibernate / JPA, это сработает.
@PrePersist
void preInsert() {
if (this.dateOfConsent == null)
this.dateOfConsent = LocalDateTime.now();
if(this.consentExpiry==null)
this.consentExpiry = this.dateOfConsent.plusMonths(3);
}
В моем случае из-за того, что поле LocalDateTime, я использовал это, рекомендуется из-за независимости от поставщика.
Это невозможно в JPA.
Вот что вы можете делать с аннотацией столбца: http://java.sun.com/javaee/5/docs/api/javax/persistence/Column.html
Ни JPA, ни аннотации Hibernate не поддерживают понятие значения столбца по умолчанию. В качестве обходного пути к этому ограничению установите все значения по умолчанию непосредственно перед вызовом спящего режима save() или update() в сеансе. Это максимально близко (за исключением Hibernate, устанавливающего значения по умолчанию) имитирует поведение базы данных, которая устанавливает значения по умолчанию при сохранении строки в таблице.
В отличие от установки значений по умолчанию в классе модели в качестве этого альтернативного ответа предполагает, что этот подход также гарантирует, что запросы критериев, использующие объект Example в качестве прототипа для поиска, будут продолжать работать, как и раньше. Когда вы устанавливаете значение по умолчанию для атрибута, допускающего значение NULL (тот, который имеет непримитивный тип) в классе модели, запрос Hibernate по примеру больше не будет игнорировать связанный столбец, где раньше он игнорировал бы его, потому что он был пустым.
Если вы используете двойной, вы можете использовать следующее:
@Column(columnDefinition="double precision default '96'")
private Double grolsh;
Да, это зависит от БД.
Вы можете определить значение по умолчанию в дизайнере базы данных или при создании таблицы. Например, в SQL Server вы можете установить для хранилища по умолчанию поля даты значение (getDate()). Используйте insertable=false, как указано в определении столбца. JPA не будет указывать этот столбец во вставках, и база данных сгенерирует значение для вас.
columnDefinitionили@ColumnDefault, рекомендуется придерживаться стандартных типов. dba.stackexchange.com/questions/53317/ < / а>. - person Oliver   schedule 22.01.2021