我的基本问题是:如何强制Hibernate使float为NULL,并分别为float,datetime,blob接受NULL?我的意思是NULL,而不是(float)0.0。
更糟糕的是,当我尝试存储一个具有所需NULLable字段的对象实际为NULL并使用实体管理器时,我得到属性的错误,即使在db表中也被Hibernate标记为NULL。
这是我一直在徒劳的尝试:
考虑下表:
+--------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(255) | NO | | NULL | |
| number | float | YES | | NULL | |
| url | varchar(3) | YES | | NULL | |
| mydate | date | YES | | NULL | |
+--------+--------------+------+-----+---------+----------------+
由这些陈述创建:
DROP SCHEMA IF EXISTS `mydb` ;
CREATE SCHEMA IF NOT EXISTS `mydb` DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ;
USE `mydb` ;
DROP TABLE IF EXISTS `mydb`.`test` ;
CREATE TABLE IF NOT EXISTS `mydb`.`test` (
`id` INT NOT NULL AUTO_INCREMENT ,
`name` VARCHAR(255) NOT NULL ,
`number` FLOAT NULL,
`url` VARCHAR(3) NULL ,
`mydate` DATE NULL ,
PRIMARY KEY (`id`) ,
UNIQUE INDEX `id_UNIQUE` (`id` ASC) )
ENGINE = InnoDB;
如果我执行以下插入:
INSERT INTO `mydb`.`test` (`name`) VALUES ('MyName');
SELECT * FROM `mydb`.`test`;
我得到以下结果:
+----+--------+--------+------+--------+
| id | name | number | url | mydate |
+----+--------+--------+------+--------+
| 1 | MyName | NULL | NULL | NULL |
+----+--------+--------+------+--------+
1 row in set (0.00 sec)
这正是我想要的。
使用Hibernate 3.5 / JPA2,我尝试像这样做我的ORM:
BO:
public class BodyStat extends BusinessObject {
@Id
private int id;
private String name;
@Column(nullable = true)
private float number;
@Column(nullable = true)
private URL url;
@Column(nullable = true)
private Date myDate;
... C'Tor / setters / getters / eof
我的orm.xml中的实体如下所示:
<entity class="test">
<table name=""test""/>
<attributes>
<id name="id">
<generated-value strategy="TABLE"/>
</id>
<basic name="name"/>
<basic name="number" optional="true"/>
<basic name="url" optional="true"/>
<basic name="myDate" optional="true"/>
</attributes>
</entity>
现在Hibernate生成的表看起来像这样:
+--------+--------------+------+-----+---------+------------+
| Field | Type | Null | Key | Default | Extra |
+--------+--------------+------+-----+---------+------------+
| id | int(11) | NO | PRI | NULL | |
| name | varchar(255) | NO | | NULL | |
| number | float | NO | | NULL | |
| url | tinyblob | YES | | NULL | |
| mydate | date | YES | | NULL | |
+--------+--------------+------+-----+---------+------------+
这不是我想要的。如你所见
答案 0 :(得分:3)
float不可为空,
这个很奇怪。 nullable
仅使用 作为表创建的列属性,并且应该执行其作业映射属性是否为基元。至少你的代码适用于Derby,我为生成的表获得了一个可为空的列。但很明显,如果你希望能够“传递”Float
值,那么在对象级别使用包装器(即null
)是有意义的。
类型“url”原来是blob而不是varchar和
从JPA 1.0规范:
2.1.1持久字段和属性
...
实体的持久字段或属性可以是以下类型:Java原始类型;
java.lang.String
;其他Java可序列化类型(包括基本类型的包装,java.math.BigInteger
,java.math.BigDecimal
,java.util.Date
,java.util.Calendar
,java.sql.Date
,java.sql.Time
,{{ 1}},用户定义的可序列化类型,java.sql.Timestamp
,byte[]
,Byte[]
和char[]
);枚举;实体类型和/或实体类型集合;和可嵌入的类(见2.1.5节)。
Character[]
是可序列化的,这是所有(从JPA的角度来看),因此它被视为可序列化(并存储在BLOB中)。
如果您确实希望将其存储为java.net.URL
,请使用自定义String
(特定于Hibernate)或使用UserType
持有者并提供进行转换的getter / setter(并将吸气剂标记为瞬态)。像这样:
String
mydate为“date”而不是“datetime”
如果您希望还存储日期的时间部分,请使用private String urlAsString;
@Transient
public URL getUrl() throws MalformedURLException {
return new URL(this.urlAsString);
}
public void setUrl(URL url) {
this.urlAsString = url.toString();
}
@Column(nullable = true)
protected String getUrlAsString() {
return urlAsString;
}
protected void setUrlAsString(String urlAsString) {
this.urlAsString = urlAsString;
}
注释将其映射为时间戳:
@Temporal
PS:顺便说一句,为什么你同时提供注释和@Column(nullable = true)
@Temporal(TemporalType.TIMESTAMP)
private Date myDate;
?你知道它们在某种程度上是等价的吗?如果您可以使用注释,只需使用它们,就不需要orm.xml
。
答案 1 :(得分:1)
再次感谢您的大力支持和建议。实际上,我现在已经找到了解决方案。正如Pascal所提到的,我一直在使用,注释驱动和xml配置混合使用。一旦我删除了xml配置,这个问题就解决了。
我不会在hibernate中打开一个bug,因为最好不要混淆配置类型,因此,我宁愿给出建议来执行最佳实践,而不是混淆配置类型。
干杯 ER
答案 2 :(得分:0)
float原语不可为空,但是java.lang.Float或java.lang.Double是。
如果这不起作用,也许你需要更抽象地思考。那个浮子代表什么? “数字”不是很具描述性。这是账户余额吗?还有什么对你的问题有意义吗?如果是,请将其包装在更好地描述和抽象的对象中。
Java是一种面向对象的语言,ORM中的“O”代表对象。在原语和关系列方面少考虑,在对象方面更多。如果你这样做,你会发现Hibernate更容易。