当前位置:  开发笔记 > 编程语言 > 正文

在JPA中设置列的默认值

如何解决《在JPA中设置列的默认值》经验,为你挑选了11个好方法。

是否可以为JPA中的列设置默认值,以及是否使用注释完成了哪些操作?



1> Pablo Ventur..:

您可以执行以下操作:

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

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

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


如果您希望实体在插入后具有正确的值,这是正确的方法.+1
在模型类中设置可为空的属性(具有非基本类型的属性)的默认值将破坏使用"Example"对象作为搜索原型的条件查询.设置默认值后,Hibernate示例查询将不再忽略先前将忽略它的关联列,因为它是null.更好的方法是在调用Hibernate`save()`或`update()`之前设置所有默认值.这更好地模仿了数据库的行为,该行为在保存行时设置了默认值.
这并不能确保为非基本类型设置默认值(例如设置`null`).使用`@ PrePersist`和`@ PreUpdate`是一个更好的选择imho.
这是指定列的默认值的正确方法.`columnDefinition`属性不与数据库无关和`@ PrePersist`插入前将覆盖你的设置,"默认值"是别的东西,如果没有设置值明确使用缺省值.

2> Cameron Pope..:

实际上它在JPA中是可能的,虽然使用注释的columnDefinition属性有点黑客@Column,例如:

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


在创建具有空字段的实体并将其保留后,您将不会在其中设置值.不是解决方案......
另请注意,此columnDefinition不一定与数据库无关,并且当然不会自动与Java中的数据类型绑定.
没有@NathanFeger,10是长度,2是小数部分.所以1234567890.12不是受支持的号码,但12345678.90有效.
如果列可以为空,则需要`insertable = false`(以避免不需要的列参数).
10是整数部分,2是数字的小数部分所以:1234567890.12是支持的数字.

3> 小智..:

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

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


@MaxNanasy`if(createdt == null)createdt = new Date();`
不应该是`if(createdt!= null)createdt = new Date();`或者什么?现在,这将覆盖显式指定的值,这似乎使它不是一个默认值.

4> Ondra Žižka..:

在2017年,JPA仍然只有@Column(columnDefinition='...')你放置列的文字SQL定义.这是非常不灵活的,并迫使您也声明其他方面,如类型,短路JPA实现的观点.

Hibernate虽然,有这个:

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

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

Hibernate 4.3 docs(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> TC1..:

看到我在试图解决同样的问题时偶然发现Google的这个问题,我只是想提一下我做过的解决方案以防有人发现它有用.

从我的观点来看,这个问题真的只有一个解决方案 - @PrePersist.如果你在@PrePersist中进行,你必须检查是否已经设置了值.


+1 - 我肯定会为OP的用例选择`@ PrePersist`.`@Column(columnDefinition = ...)`似乎不太优雅.

7> 小智..:
@Column(columnDefinition="tinyint(1) default 1")

我刚刚测试了这个问题.它工作得很好.谢谢你的提示.


关于评论:

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

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


**它在对象级别上工作不正常**(在实体中插入后,您将无法获得数据库默认值).默认为Java级别.

8> 小智..:

我用columnDefinition,它的效果非常好

@Column(columnDefinition="TIMESTAMP DEFAULT CURRENT_TIMESTAMP")

private Date createdDate;


这看起来像是让你的jpa实现供应商具体.

9> Thomas Zhang..:

你可以用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> Timo..:

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



11> Xiè Jìléi..:

在我的例子中,我修改了hibernate-core源代码,以便引入一个新的注释@DefaultValue:

commit 34199cba96b6b1dc42d0d19c066bd4d119b553d5
Author: Lenik 
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 );

嗯,这是一个仅限hibernate的解决方案.


虽然我非常感谢积极参与开源项目的人们的努力,但我赞成这个答案,因为JPA是任何OR/M之上的标准Java规范,OP要求JPA方式来指定默认值并且您的补丁工作仅适用于Hibernate.如果这是NHibernate,其中没有*super-partes*规范的持久性(甚至MS EF甚至不支持NPA),我会赞成这样的补丁.事实是,与ORM的要求相比,JPA非常有限(一个例子:没有二级索引).无论如何,努力的荣誉
推荐阅读
ERIK又
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有