Hibernate / JPA - >可空的价值和对象?

时间:2010-07-11 23:47:23

标签: java hibernate orm jpa nullable

我的基本问题是:如何强制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="&quot;test&quot;"/>
    <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    |            |
+--------+--------------+------+-----+---------+------------+

这不是我想要的。如你所见

  1. float不可为空,
  2. 类型“url”原来是blob而不是varchar和
  3. mydate as“date”而不是“datetime”

3 个答案:

答案 0 :(得分:3)

  

float不可为空,

这个很奇怪。 nullable仅使用 作为表创建的列属性,并且应该执行其作业映射属性是否为基元。至少你的代码适用于Derby,我为生成的表获得了一个可为空的列。但很明显,如果你希望能够“传递”Float值,那么在对象级别使用包装器(即null)是有意义的。

  

类型“url”原来是blob而不是varchar和

从JPA 1.0规范:

  

2.1.1持久字段和属性

     

...

     

实体的持久字段或属性可以是以下类型:Java原始类型; java.lang.String;其他Java可序列化类型(包括基本类型的包装,java.math.BigIntegerjava.math.BigDecimaljava.util.Datejava.util.Calendarjava.sql.Datejava.sql.Time,{{ 1}},用户定义的可序列化类型,java.sql.Timestampbyte[]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更容易。