2008-10-13 138 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我用这个,这是由于供应商独立性