279

是否可以为 JPA 中的列设置默认值,如果使用注释,它是如何完成的?

4

19 回答 19

343

您可以执行以下操作:

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

那里!您刚刚使用零作为默认值。

请注意,如果您仅从此应用程序访问数据库,这将为您服务。如果其他应用程序也使用数据库,那么您应该使用Cameron 的 columnDefinition注释属性或其他方式从数据库中进行此检查。

于 2009-06-18T15:54:25.530 回答
259

columnDefinition实际上,在 JPA 中是可能的,尽管使用注释的属性有点小技巧@Column,例如:

@Column(name="Price", columnDefinition="Decimal(10,2) default '100.00'")
于 2008-12-17T16:44:06.493 回答
122

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

@PrePersist
void preInsert() {
   if (this.createdTime == null)
       this.createdTime = new Date();
}
于 2012-11-17T16:02:31.543 回答
60

在 2017 年,JPA 2.1 仍然只有@Column(columnDefinition='...')您在其中放置列的文字 SQL 定义。这是非常不灵活的,并迫使您还声明类型等其他方面,从而缩短了 JPA 实现对此事的看法。

休眠虽然,有这个:

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

标识通过 DDL 应用于关联列的 DEFAULT 值。

对此有两点说明:

1)不要害怕不标准。作为一名 JBoss 开发人员,我见过不少规范流程。该规范基本上是给定领域的大玩家愿意承诺在未来十年左右提供支持的基线。对于安全来说确实如此,对于消息传递来说,ORM 没有区别(尽管 JPA 涵盖了很多内容)。我作为开发人员的经验是,在一个复杂的应用程序中,迟早你会需要一个非标准的 API。并且@ColumnDefault是一个例子,它超过了使用非标准解决方案的负面影响。

2)每个人都如何挥动@PrePersist 或构造函数成员初始化,这很好。但这不一样。批量 SQL 更新怎么样?不设置列的语句怎么样?DEFAULT有它的作用,并且不能通过初始化 Java 类成员来替代。

于 2017-02-10T03:21:58.160 回答
14

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 自动装箱在这方面有很大帮助。

于 2010-04-12T12:38:17.453 回答
10
@Column(columnDefinition="tinyint(1) default 1")

我刚刚测试了这个问题。它工作得很好。感谢您的提示。


关于评论:

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

这个没有设置数据库中的默认列值(当然)。

于 2010-03-31T16:45:16.547 回答
10

看到我在尝试解决同样的问题时从谷歌偶然发现了这个,我只是将我准备好的解决方案扔进去,以防有人发现它有用。

从我的角度来看,这个问题实际上只有 1 个解决方案——@PrePersist。如果您在@PrePersist 中执行此操作,则必须检查该值是否已经设置。

于 2010-11-12T17:37:45.287 回答
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();
            }
        }
    }
于 2016-04-05T10:02:47.607 回答
8

我用过columnDefinition,效果很好

@Column(columnDefinition="TIMESTAMP DEFAULT CURRENT_TIMESTAMP")

private Date createdDate;
于 2012-01-05T21:49:12.027 回答
7

您不能使用列注释来执行此操作。我认为唯一的方法是在创建对象时设置默认值。也许默认构造函数是这样做的正确位置。

于 2008-12-06T22:08:23.863 回答
5

就我而言,我修改了 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 谢继雷
+ */
+@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 );

好吧,这是一个仅限休眠的解决方案。

于 2011-12-21T05:34:11.593 回答
5
  1. @Column(columnDefinition='...')插入数据时在数据库中设置默认约束时不起作用。
  2. 您需要从注释中创建insertable = false和删除columnDefinition='...',然后数据库将自动从数据库中插入默认值。
  3. 例如,当您在数据库中设置 varchar 时,性别默认为男性。
  4. 您只需要添加insertable = falseHibernate/JPA 即可。
于 2017-06-27T22:40:51.107 回答
3
@PrePersist
void preInsert() {
    if (this.dateOfConsent == null)
        this.dateOfConsent = LocalDateTime.now();
    if(this.consentExpiry==null)
        this.consentExpiry = this.dateOfConsent.plusMonths(3);
}

在我的情况下,由于字段是 LocalDateTime 我使用了这个,由于供应商独立性,建议使用它

于 2017-10-11T12:43:54.783 回答
2

这在 JPA 中是不可能的。

以下是您可以使用 Column 注释执行的操作:http: //java.sun.com/javaee/5/docs/api/javax/persistence/Column.html

于 2008-10-13T09:10:06.483 回答
2

如果您使用的是双打,您可以使用以下内容:

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

private Double grolsh;

是的,它是特定于数据库的。

于 2012-02-08T10:24:18.333 回答
1

JPA 和 Hibernate 注释都不支持默认列值的概念。作为此限制的解决方法,请在调用 Hibernate 之前save()update()在会话上设置所有默认值。这尽可能地(没有 Hibernate 设置默认值)模仿数据库的行为,当它在表中保存一行时设置默认值。

与此替代答案所建议的在模型类中设置默认值不同,此方法还确保使用Example对象作为搜索原型的条件查询将继续像以前一样工作。当您在模型类中设置可空属性(具有非原始类型的属性)的默认值时,Hibernate 示例查询将不再忽略之前因为它为空而忽略它的关联列。

于 2010-08-03T20:13:29.807 回答
1

您可以在数据库设计器中定义默认值,也可以在创建表时定义。例如,在 SQL Server 中,您可以将 Date 字段的默认 Vault 设置为 ( getDate())。insertable=false按照列定义中的说明使用。JPA 不会在插入时指定该列,数据库将为您生成值。

于 2016-03-03T00:41:23.753 回答
0

我找到了解决相同问题的另一种方法,因为当我创建自己的对象并保存在数据库中并且不尊重具有默认值的 DDL 时。

所以我查看了我的控制台,生成了 SQL,并看到 insert 带有所有字段,但我的对象中只有一个属性的值发生了变化。

所以我在模型类中放了这个注解。

@DynamicInsert

插入数据时,框架不插入空值或未修改的值,使插入时间更短。

还有@DynamicUpdate注释。

于 2021-10-19T19:57:28.763 回答
0

我尝试了几种 JPA/Hiberate 方法,但似乎没有一种效果很好。由于我使用的是 Oracle,因此我在触发器中创建了一个“前触发器”,对 null 进行简单测试,然后根据需要设置 null

于 2021-10-22T01:06:32.567 回答