Можно ли установить значение по умолчанию для столбцов в JPA, и если, как это делается с помощью аннотаций?
Установка значений по умолчанию для столбцов в JPA
Ответ 1
На самом деле это возможно в JPA, хотя немного взломать, используя свойство columnDefinition
аннотации @Column
, например:
@Column(name="Price", columnDefinition="Decimal(10,2) default '100.00'")
Ответ 2
Вы можете сделать следующее:
@Column(name="price")
private double price = 0.0;
Там! Вы только что использовали нулевое значение по умолчанию.
Обратите внимание, что это будет служить вам, если вы только получаете доступ к базе данных из этого приложения. Если другие приложения также используют базу данных, вы должны сделать эту проверку из базы данных, используя атрибут примечания columnDefinition от Cameron или каким-либо другим способом.
Ответ 3
другой подход использует javax.persistence.PrePersist
@PrePersist
void preInsert() {
if (this.createdTime == null)
this.createdTime = new Date();
}
Ответ 4
В 2017 году у JPA все еще есть только @Column(columnDefinition='...')
в которое вы помещаете буквальное определение SQL столбца. Что является довольно негибким и заставляет вас также объявлять другие аспекты, такие как тип, закорачивая представление реализации JPA по этому вопросу.
Hibernate, хотя, имеет это:
@Column(length = 4096, nullable = false)
@org.hibernate.annotations.ColumnDefault("")
private String description;
Определяет значение DEFAULT для применения к связанному столбцу с помощью DDL.
- Hibernate 4.3 документа (4.3, чтобы показать, что он был здесь в течение достаточно долгого времени)
- Руководство Hibernate по значению по умолчанию для столбца базы данных
Два примечания к этому:
1) Не бойтесь идти нестандартно. Работая в качестве разработчика JBoss, я видел довольно много процессов спецификации. Спецификация - это в основном базовая линия, которую крупные игроки в данной области готовы взять на себя обязательство поддержать в течение следующего десятилетия или около того. Это верно для безопасности, для обмена сообщениями, ORM не имеет значения (хотя JPA охватывает довольно много). Мой опыт разработчика заключается в том, что в сложных приложениях рано или поздно вам все равно понадобится нестандартный API. И @ColumnDefault
- пример, когда он перевешивает недостатки использования нестандартного решения.
2) Приятно, что каждый машет инициализацией @PrePersist или членом конструктора. Но это НЕ то же самое. Как насчет массовых обновлений SQL? Как насчет утверждений, которые не устанавливают столбец? DEFAULT
выполняет свою роль и не может быть заменен инициализацией члена класса Java.
Ответ 5
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-бокс очень помогает в этом.
Ответ 6
Увидев, как я наткнулся на это от Google, пытаясь решить ту же проблему, я просто заброшу решение, которое я приготовил, если кто-то сочтет это полезным.
С моей точки зрения, действительно существует только 1 решение этой проблемы - @PrePersist. Если вы это сделаете в @PrePersist, вам нужно проверить, было ли уже установлено значение.
Ответ 7
@Column(columnDefinition="tinyint(1) default 1")
Я только что протестировал проблему. Он отлично работает. Спасибо за подсказку.
О комментариях:
@Column(name="price")
private double price = 0.0;
Этот не устанавливает значение столбца по умолчанию в базе данных (конечно).
Ответ 8
Я использую columnDefinition
, и он работает очень хорошо
@Column(columnDefinition="TIMESTAMP DEFAULT CURRENT_TIMESTAMP")
private Date createdDate;
Ответ 9
вы можете использовать java-отражение 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();
}
}
}
Ответ 10
Вы не можете сделать это с помощью аннотации столбца. Я думаю, что единственный способ - установить значение по умолчанию при создании объекта. Может быть, конструктор по умолчанию будет правильным местом для этого.
Ответ 11
В моем случае я изменил исходный код спящего ядра, ну, чтобы ввести новую аннотацию @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 })
[email protected](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 );
Ну, это решение только для спящего режима.
Ответ 12
Ни аннотации JPA, ни Hibernate не поддерживают понятие значения столбца по умолчанию. В качестве обходного пути к этому ограничению установите все значения по умолчанию непосредственно перед вызовом Hibernate save()
или update()
в сеансе. Это настолько близко, насколько это возможно (не дожидаясь установки Hibernate по умолчанию) имитирует поведение базы данных, которая устанавливает значения по умолчанию при сохранении строки в таблице.
В отличие от установки значений по умолчанию в классе модели, как это предлагает альтернативный ответ, этот подход также гарантирует, что критерии запросов, которые используют объект Example
в качестве прототипа для поиск будет продолжать работать по-прежнему. Когда вы устанавливаете значение по умолчанию для атрибута с нулевым значением (тот, который имеет не-примитивный тип) в классе модели, пример запроса Hibernate больше не будет игнорировать соответствующий столбец, где ранее он игнорировал бы его, потому что он был нулевым.
Ответ 13
@PrePersist
void preInsert() {
if (this.dateOfConsent == null)
this.dateOfConsent = LocalDateTime.now();
if(this.consentExpiry==null)
this.consentExpiry = this.dateOfConsent.plusMonths(3);
}
В моем случае из-за того, что поле LocalDateTime я использовал это, рекомендуется из-за независимости поставщика
Ответ 14
Если вы используете двойной, вы можете использовать следующее:
@Column(columnDefinition="double precision default '96'")
private Double grolsh;
Да, это db specific.
Ответ 15
-
@Column(columnDefinition='...')
не работает, когда вы устанавливаете ограничение по умолчанию в базе данных при вставке данных. - Вам нужно сделать
insertable = false
и удалитьcolumnDefinition='...'
из аннотации, тогда база данных автоматически добавит значение по умолчанию из базы данных. - например. когда вы устанавливаете varchar gender, по умолчанию используется по умолчанию в базе данных.
- Вам просто нужно добавить
insertable = false
в Hibernate/JPA, он будет работать.
Ответ 16
Это невозможно в JPA.
Вот что вы можете сделать с аннотацией столбца: http://java.sun.com/javaee/5/docs/api/javax/persistence/Column.html
Ответ 17
Вы можете определить значение по умолчанию в дизайнере базы данных или при создании таблицы. Например, в SQL Server вы можете установить хранилище по умолчанию поля Date (getDate()
). Используйте insertable=false
, как указано в определении столбца. JPA не будет указывать этот столбец на вставках, и база данных будет генерировать значение для вас.
Ответ 18
Вам нужно insertable=false
в аннотации @Column
. JPA будет игнорировать этот столбец при вставке в базу данных и значение по умолчанию.
Смотрите эту ссылку: http://mariemjabloun.blogspot.com/2014/03/resolved-set-database-default-value-in.html