是否可以为JPA中的列设置默认值,以及是否使用注释完成了哪些操作?
您可以执行以下操作:
@Column(name="price") private double price = 0.0;
那里!您刚刚使用零作为默认值.
请注意,如果您只是从此应用程序访问数据库,这将为您服务.如果其他应用程序也使用数据库,那么您应该使用Cameron的 columnDefinition批注属性或其他方式从数据库进行此检查.
实际上它在JPA中是可能的,虽然使用注释的columnDefinition
属性有点黑客@Column
,例如:
@Column(name="Price", columnDefinition="Decimal(10,2) default '100.00'")
另一种方法是使用javax.persistence.PrePersist
@PrePersist void preInsert() { if (this.createdTime == null) this.createdTime = new Date(); }
在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类成员来替代.
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自动拳击对此有很大帮助.
看到我在试图解决同样的问题时偶然发现Google的这个问题,我只是想提一下我做过的解决方案以防有人发现它有用.
从我的观点来看,这个问题真的只有一个解决方案 - @PrePersist.如果你在@PrePersist中进行,你必须检查是否已经设置了值.
@Column(columnDefinition="tinyint(1) default 1")
我刚刚测试了这个问题.它工作得很好.谢谢你的提示.
关于评论:
@Column(name="price") private double price = 0.0;
这个不设置数据库中的默认列值(当然).
我用columnDefinition
,它的效果非常好
@Column(columnDefinition="TIMESTAMP DEFAULT CURRENT_TIMESTAMP") private Date createdDate;
你可以用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(); } } }
您不能使用列注释执行此操作.我认为唯一的方法是在创建对象时设置默认值.也许默认构造函数是正确的地方.
在我的例子中,我修改了hibernate-core源代码,以便引入一个新的注释@DefaultValue
:
commit 34199cba96b6b1dc42d0d19c066bd4d119b553d5 Author: LenikDate: 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的解决方案.