代码之家  ›  专栏  ›  技术社区  ›  homaxto

为JPA中的列设置默认值

  •  212
  • homaxto  · 技术社区  · 16 年前

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

    18 回复  |  直到 6 年前
        1
  •  201
  •   Jasper wontondon    13 年前

    实际上,在JPA中是可能的,尽管有一点黑客使用 columnDefinition 性质 @Column 注释,例如:

    @Column(name="Price", columnDefinition="Decimal(10,2) default '100.00'")
    
        2
  •  267
  •   Community CDub    7 年前

    您可以执行以下操作:

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

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

    注意:如果您只从这个应用程序访问数据库,那么这将为您服务。如果其他应用程序也使用该数据库,则应使用 Cameron's 列定义 注释属性或其他方式。

        3
  •  95
  •   Ondra Žižka David Lilljegren    7 年前

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

    @PrePersist
    void preInsert() {
       if (this.createdTime == null)
           this.createdTime = new Date();
    }
    
        4
  •  31
  •   Ondra Žižka David Lilljegren    6 年前

    2017年,JPA仍然只有 @Column(columnDefinition='...') 将列的字面SQL定义放入其中。这是非常不灵活的,并且强制您声明其他方面,比如类型,从而使JPA实现在这方面的观点短路。

    不过,冬眠是这样的:

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

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

    两个注意事项:

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

    2)很高兴大家都在挥动@preversist或构造函数成员初始化。但情况不同。批量SQL更新如何?不设置列的语句如何? DEFAULT 它的作用并不是通过初始化Java类成员而替代的。

        5
  •  13
  •   community wiki 2 revs, 2 users 72% Marco    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自动装箱在这方面有很大帮助。

        6
  •  9
  •   TC1    14 年前

    当我试图解决同样的问题时,在谷歌上偶然发现了这一点,我会把我准备的解决方案扔进去,以防有人发现它有用。

    从我的观点来看,这个问题只有1个解决方案——@preversist。如果你在@prepersist中这样做,你必须检查这个值是否已经设置好了。

        7
  •  7
  •   Stu Thompson Helter Scelter    13 年前
    @Column(columnDefinition="tinyint(1) default 1")
    

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


    关于评论:

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

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

        8
  •  7
  •   Thomas Zhang    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();
                }
            }
        }
    
        9
  •  6
  •   Udo Held    13 年前

    我用 columnDefinition 而且效果很好

    @Column(columnDefinition="TIMESTAMP DEFAULT CURRENT_TIMESTAMP")
    
    private Date createdDate;
    
        10
  •  6
  •   Piotr Nowicki    12 年前

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

        11
  •  5
  •   Lenik    13 年前

    在我的例子中,我修改了Hibernate核心源代码来引入一个新的注释 @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 );
    

    好吧,这只是一个休眠解决方案。

        12
  •  2
  •   Community CDub    7 年前

    JPA和Hibernate注释都不支持默认列值的概念。为了解决这个限制,在调用休眠之前设置所有默认值。 save() update() 在会议上。这将尽可能模拟数据库的行为(除了Hibernate设置默认值之外),该数据库在表中保存行时设置默认值。

    不同于将模型类中的默认值设置为 alternative answer 建议,此方法还确保使用 Example 对象作为搜索的原型将继续工作。在模型类中设置可以为空的属性(具有非基元类型的属性)的默认值时,通过示例进行的休眠查询将不再忽略先前将忽略它的关联列,因为它是空的。

        13
  •  2
  •   Mohammed Rafeeq    7 年前
    @PrePersist
    void preInsert() {
        if (this.dateOfConsent == null)
            this.dateOfConsent = LocalDateTime.now();
        if(this.consentExpiry==null)
            this.consentExpiry = this.dateOfConsent.plusMonths(3);
    }
    

    在我的示例中,由于字段为localdatetime,所以建议使用该字段,因为供应商独立

        14
  •  1
  •   Gal Bracha    13 年前

    如果您使用的是双人床,则可以使用以下选项:

    @Column(columnDefinition="double precision default '96'")
    
    private Double grolsh;
    

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

        15
  •  1
  •   bluish dmajkic    7 年前
    1. @Column(columnDefinition='...') 插入数据时在数据库中设置默认约束时不起作用。
    2. 你需要做 insertable = false 去除 columnDefinition='...' 从注释中,数据库将自动插入数据库中的默认值。
    3. 例如,在数据库中设置varchar gender时,默认情况下为男性。
    4. 你只需要添加 可插入=假 在hibernate/jpa中,它将工作。
        16
  •  0
  •   PEELY    16 年前

    这在JPA中是不可能的。

    这就是你 可以 使用列注释: http://java.sun.com/javaee/5/docs/api/javax/persistence/Column.html

        17
  •  0
  •   bluish dmajkic    9 年前

    可以在数据库设计器中或在创建表时定义默认值。例如,在SQL Server中,可以将日期字段的默认保管库设置为( getDate() )使用 insertable=false 如列定义中所述。JPA不会在插入时指定该列,数据库将为您生成该值。

        18
  •  -2
  •   bluish dmajkic    10 年前

    你需要 insertable=false 在你 @Column 注释。JPA将在数据库中插入时忽略该列,并将使用默认值。

    看到这个链接: http://mariemjabloun.blogspot.com/2014/03/resolved-set-database-default-value-in.html