JPA에서 열의 기본값을 설정할 수 있습니까? 그렇다면 주석을 사용하여 어떻게 수행합니까?
JPA에서 열의 기본값을 설정할 수 있습니까? 그렇다면 주석을 사용하여 어떻게 수행합니까?
답변:
실제로 JPA에서 가능하지만 주석 의 columnDefinition
속성을 사용하는 약간의 해킹 은 다음과 @Column
같습니다.
@Column(name="Price", columnDefinition="Decimal(10,2) default '100.00'")
insertable=false
컬럼이 널 (NULL) 인 경우 (그리고 불필요한 열 인수를 피하기 위해).
다음을 수행 할 수 있습니다.
@Column(name="price")
private double price = 0.0;
그곳에! 방금 기본값으로 0을 사용했습니다.
이 응용 프로그램에서만 데이터베이스에 액세스하는 경우이 기능이 제공됩니다. 다른 응용 프로그램도 데이터베이스를 사용하는 경우 Cameron의 columnDefinition 주석 속성 또는 다른 방법을 사용하여 데이터베이스에서이 검사를 수행해야합니다 .
Example
오브젝트를 검색의 프로토 타입으로 사용하는 기준 조회가 중단됩니다 . 기본값을 설정 한 후, Hibernate 예제 쿼리는 이전에 널 (null)이기 때문에이를 무시했던 연관된 열을 더 이상 무시하지 않습니다. 더 나은 방법은 하이버 네이트 호출하기 전에 모든 기본 값을 설정하는 것입니다 save()
또는 update()
. 이것은 행을 저장할 때 기본값을 설정하는 데이터베이스의 동작을 더 잘 모방합니다.
null
예 : 설정)에 대해 기본값이 설정되도록 보장하지 않습니다 . 사용 @PrePersist
하고 @PreUpdate
더 나은 옵션 imho입니다.
columnDefinition
속성은 데이터베이스와 무관하며 @PrePersist
삽입 전에 설정을 재정의합니다. "기본값"은 다른 값이며, 값이 명시 적으로 설정되지 않은 경우 기본값이 사용됩니다.
또 다른 접근법은 javax.persistence.PrePersist를 사용하는 것입니다.
@PrePersist
void preInsert() {
if (this.createdTime == null)
this.createdTime = new Date();
}
if (createdt != null) createdt = new Date();
않습니까? 현재 명시 적으로 지정된 값을 무시하여 실제로 기본값이 아닌 것으로 보입니다.
if (createdt == null) createdt = new Date();
null
수표를 추가했습니다 .
2017 년에도 JPA 2.1 @Column(columnDefinition='...')
에는 열의 리터럴 SQL 정의 만 넣을 수 있습니다. 이것은 상당히 융통성이 없으며 유형과 같은 다른 측면을 선언하여 해당 문제에 대한 JPA 구현의 견해를 단축시켜야합니다.
그러나 최대 절전 모드는 다음과 같습니다.
@Column(length = 4096, nullable = false)
@org.hibernate.annotations.ColumnDefault("")
private String description;
DDL을 통해 연관된 열에 적용 할 DEFAULT 값을 식별합니다.
그것에 대한 두 가지 메모 :
1) 비표준으로가는 것을 두려워하지 마십시오. JBoss 개발자로 일하면서 꽤 많은 사양 프로세스를 보았습니다. 사양은 기본적으로 주어진 분야의 대기업들이 향후 10 년 정도 동안 지원하기로 약속 한 기준입니다. 보안, 메시징, ORM은 차이가 없습니다 (JPA는 상당히 많은 것을 다루지 만). 개발자로서의 경험은 복잡한 응용 프로그램에서 조만간 비표준 API가 필요하다는 것입니다. 과@ColumnDefault
비표준 솔루션을 사용하는 것의 단점을 능가하는 예입니다.
2) 모두가 @PrePersist 또는 생성자 멤버 초기화를 흔들어 놓는 것이 좋습니다. 그러나 그것은 동일하지 않습니다. 대량 SQL 업데이트는 어떻습니까? 열을 설정하지 않은 문장은 어떻습니까? DEFAULT
역할이 있으며 Java 클래스 멤버를 초기화하여 대체 할 수는 없습니다.
JPA는이를 지원하지 않으며, 가능하다면 유용 할 것입니다. columnDefinition을 사용하는 것은 DB에 따라 다르며 많은 경우 허용되지 않습니다. 널 (NULL) 값을 갖는 레코드를 검색 할 때 클래스에서 기본값을 설정하는 것만으로는 충분하지 않습니다 (일반적으로 이전 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=...)
매우 우아하지 않은 것 같습니다.
@Column(columnDefinition="tinyint(1) default 1")
방금 문제를 테스트했습니다. 잘 작동합니다. 힌트 주셔서 감사합니다.
의견에 관하여 :
@Column(name="price")
private double price = 0.0;
이것은 데이터베이스의 기본 열 값을 설정 하지 않습니다 (물론).
당신은 자바 반영 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
. 그 이유는 게으른 프로그래머가 실수를 피하는 것입니다. ;-)
나는 사용 columnDefinition
하고 아주 잘 작동합니다
@Column(columnDefinition="TIMESTAMP DEFAULT CURRENT_TIMESTAMP")
private Date createdDate;
필자의 경우 새로운 주석을 도입하기 위해 최대 절전 모드 소스 코드를 수정했습니다. @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 谢继雷
+ */
+@java.lang.annotation.Target({ 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='...'
주석에서 하면 데이터베이스가 데이터베이스에서 기본값을 자동으로 삽입합니다.insertable = false
Hibernate / JPA 를 추가 하면됩니다.JPA 또는 최대 절전 모드 주석은 기본 열 값의 개념을 지원하지 않습니다. 이 제한에 대한 임시 해결책으로, 최대 절전 모드를 호출하기 직전 save()
또는 update()
세션에서 모든 기본값을 설정하십시오 . 이것은 가능한 한 밀접하게 (기본 설정을 최대 절전 모드로 설정하지 않음) 행을 테이블에 저장할 때 기본값을 설정하는 데이터베이스의 동작을 모방합니다.
이 대안 답변에서 제안하는 것처럼 모델 클래스에서 기본값을 설정하는 것과 달리이 방법을 사용 Example
하면 검색 프로토 타입으로 객체 를 사용하는 기준 쿼리가 이전과 같이 계속 작동합니다. 모델 클래스에서 nullable 속성 (기본이 아닌 유형을 가진 속성)의 기본값을 설정하면 Hibernate query-by-query는 이전에 null이기 때문에 무시했던 관련 열을 더 이상 무시하지 않습니다.
JPA에서는 불가능합니다.
열 주석으로 수행 할 수있는 작업은 다음과 같습니다 . http://java.sun.com/javaee/5/docs/api/javax/persistence/Column.html
당신은 필요 insertable=false
당신에@Column
주석에 . JPA는 데이터베이스에 삽입하는 동안 해당 열을 무시하고 기본값이 사용됩니다.
이 링크를 참조하십시오 : http://mariemjabloun.blogspot.com/2014/03/resolved-set-database-default-value-in.html
nullable=false
실패합니다 . 여기에서로 "생성 된"타임 스탬프를 설정하는 것을 잊었습니다 . 이것은 일관성을 유지하는 좋은 방법이지만 질문자가 묻지 않은 것입니다. SqlException
Caused by: java.sql.SQLException: Column 'opening_times_created' cannot be null
openingTime.setOpeningCreated(new Date())