2008-10-13 141 views
176

是否可以爲JPA中的列設置默認值,以及如何使用註釋完成該操作?在JPA中設置列的默認值

+0

推薦的是那裏的JPA規格說明我在哪裏可以把默認值一列值另一列,因爲我希望它被隱藏起來 – shareef 2016-08-08 08:04:28

+0

相關:Hibernate有[@ org.hibernate.annotations.ColumnDefault(「foo」)](https://docs.jboss.org/hibernate/orm/4.3/javadocs/ org/hibernate/annotations/ColumnDefault.html) – 2017-02-10 03:26:38

回答

175

其實有可能在JPA,雖然使用@Column註釋的columnDefinition財產的黑客,例如一點點:

@Column(name="Price", columnDefinition="Decimal(10,2) default '100.00'") 
+0

十進制(10,2),10和2代表什麼? – Schildmeijer 2009-04-09 12:42:19

+3

10是Integer部分,2是數字的小數部分,因此: 1234567890.12將是受支持的數字。 – 2009-05-08 14:50:00

+20

另請注意,這個ColumnDefinition不一定是數據庫獨立的,當然也不會自動綁定Java中的數據類型。 – 2009-05-08 14:50:40

1

這在JPA中是不可能的。

這裏就是你可以做Column註釋:http://java.sun.com/javaee/5/docs/api/javax/persistence/Column.html

+1

不能指定默認值似乎是JPA批註的嚴重缺陷。 – 2010-06-14 19:33:14

+2

JDO允許在其ORM定義中使用JPA,因此JPA應該包含此...有一天 – user383680 2010-10-03 13:29:25

+0

您肯定**可以**,使用columnDefinition屬性來執行此操作,正如Cameron Pope所回答的。 – IntelliData 2016-02-19 15:10:39

6

你不能用列註解做到這一點。我認爲唯一的方法是在創建對象時設置默認值。也許默認的構造函數將是正確的地方。

+0

好主意。可悲的是,沒有`@ Column`的通用註釋或屬性。我也想念正在設置的評論(取自Java的doctag)。 – Roland 2017-10-13 22:09:56

223

你可以做到以下幾點:

@Column(name="price") 
private double price = 0.0; 

那裏!您剛剛使用零作爲默認值。

請注意,如果您只是從此應用程序訪問數據庫,這將爲您提供服務。如果其他應用程序也使用該數據庫,那麼您應該使用Cameron'scolumnDefinition註釋屬性或其他方式從數據庫進行此檢查。

6
@Column(columnDefinition="tinyint(1) default 1") 

我剛剛測試過這個問題。 它工作得很好。感謝您的提示。


關於評論:

@Column(name="price") 
private double price = 0.0; 

這一個數據庫(當然)設置默認列值。

13

JPA不支持這一點,如果它確實會有用。使用columnDefinition是特定於DB的,在許多情況下不可接受。當您檢索具有空值的記錄時(通常在您重新運行舊的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自動裝箱功能對此有很大的幫助。

2

JPA和Hibernate註釋都不支持默認列值的概念。作爲解決此限制的一種解決方法,請在會話上調用Hibernate save()update()之前設置所有默認值。儘可能接近(Hibernate設置缺省值)模仿數據庫的行爲,當數據庫在表中保存行時,它設置默認值。

與在alternative answer建議的模型類中設置默認值不同,此方法還確保將使用Example對象作爲搜索原型的條件查詢將繼續像以前一樣工作。當您在模型類中設置nullable屬性(非基元類型的屬性)的默認值時,Hibernate逐個查詢將不再忽略之前忽略它的關聯列,因爲它是空的。

8

看到我在試圖解決同樣的問題時偶然發現了這個問題,我只是想扔掉我製作的解決方案,以防有人發現它有用。

從我的角度來看,這個問題真的只有1個解決方案 - @PrePersist。如果你在@PrePersist中做,你必須檢查是否已經設置了該值。

5

就我而言,我修改了休眠核心源代碼,很好,引進了新的註釋@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); 

好了,這是一個只有Hibernate的解決方案。

6

我用columnDefinition,它如果您使用的是雙重的作品非常好

@Column(columnDefinition="TIMESTAMP DEFAULT CURRENT_TIMESTAMP") 

private Date createdDate; 
1

,您可以使用以下命令:

@Column(columnDefinition="double precision default '96'") 

private Double grolsh; 

是它的分貝具體。

78

另一種方法是使用javax.persistence.PrePersist

@PrePersist 
void preInsert() { 
    if (this.createdTime == null) 
     this.createdTime = new Date(); 
} 
0

可以在數據庫設計器定義的默認值,或當您創建表。例如,在SQL Server中,您可以將日期字段的默認保管庫設置爲(getDate())。如列定義中所述,使用insertable=false。 JPA不會在插入時指定該列,並且數據庫將爲您生成值。

5

您可以使用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(); 
      } 
     } 
    } 
15

在2017年,JPA仍然只有@Column(columnDefinition='...')到你把列的文本SQL定義。這是非常不靈活的,並且迫使你也聲明其他方面的類型,並將JPA實現對此問題的看法縮短。

休眠不過,有這樣的:

@Column(length = 4096, nullable = false) 
@org.hibernate.annotations.ColumnDefault("") 
private String description; 

標識默認值適用於通過DDL相關聯的列。

Hibernate 4.3 docs(4。3,以顯示它已經在這裏相當長的一段時間)
休眠手冊上Default value for database column

兩個音符到:

1)不要怕要去非標準。作爲一名JBoss開發人員,我已經看到了一些規範流程。該規範基本上是給定領域的大玩家願意承諾在未來十年左右支持的基準。對於安全性來說,對於消息傳遞來說,ORM沒有什麼區別(儘管JPA涵蓋了很多)。作爲一名開發人員,我的經歷是,在一個複雜的應用程序中,無論如何你遲早都會需要一個非標準的API。而@ColumnDefault就是一個例子,它超過了標準解決方案的負面影響。

2)很高興大家如何揮手@PrePersist或構造函數成員初始化。但那不是一回事。如何批量SQL更新?如何處理不設置列的語句? DEFAULT具有它的作用,並且通過初始化Java類成員不可替代。

0
  1. @Column(columnDefinition='...')在插入數據時設置數據庫中的默認約束時不起作用。
  2. 您需要製作insertable = false並從註釋中刪除columnDefinition='...',然後數據庫會自動從數據庫中插入默認值。
  3. E.g.當你設置varchar時,數據庫中的性別默認爲男性。
  4. 你只需要在Hibernate/JPA中添加insertable = false就可以了。
1
@PrePersist 
void preInsert() { 
    if (this.dateOfConsent == null) 
     this.dateOfConsent = LocalDateTime.now(); 
    if(this.consentExpiry==null) 
     this.consentExpiry = this.dateOfConsent.plusMonths(3); 
} 

在我的情況,由於現場是LocalDateTime我用這個,這是由於供應商獨立性