java Hibernate / JPA -> Nullable 值和对象?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3225103/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 00:52:47  来源:igfitidea点击:

Hibernate / JPA -> Nullable values & objects?

javahibernateormjpanullable

提问by Ta Sas

My basic question is: How can I force Hibernate to make float NULLable and accept NULL for float, datetime, blob, respectively? I really mean NULL, not (float) 0.0.

我的基本问题是:如何强制 Hibernate 分别使 float 为 NULLable 并接受 NULL for float、datetime、blob?我的意思是 NULL,而不是 (float) 0.0。

Even worse, when I try to store an object with the desired NULLable fields actually being NULL and using entity manager, I get errors for attributes, which are marked as NULLable by Hibernate even in the db table.

更糟糕的是,当我尝试存储一个对象,其中所需的 NULLable 字段实际上是 NULL 并使用实体管理器时,我收到属性错误,即使在 db 表中,这些属性也被 Hibernate 标记为 NULLable。

Here is what I have been trying in vain:

这是我一直在徒劳的尝试:

Consider this table:

考虑这个表:

+--------+--------------+------+-----+---------+----------------+
| 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    |                |
+--------+--------------+------+-----+---------+----------------+

which was created by these statements:

这是由这些语句创建的:

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;

If I carry out following insert:

如果我执行以下插入:

INSERT INTO `mydb`.`test` (`name`) VALUES ('MyName');
SELECT * FROM `mydb`.`test`;

I get following result:

我得到以下结果:

+----+--------+--------+------+--------+
| id | name   | number | url  | mydate |
+----+--------+--------+------+--------+
|  1 | MyName |   NULL | NULL | NULL   |
+----+--------+--------+------+--------+
1 row in set (0.00 sec)

which is exactly what I want.

这正是我想要的。

With Hibernate 3.5 / JPA2, I try do do my ORM like this:

使用 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

and the entity in my orm.xml looks like this:

我的 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>

Now the table generated by Hibernate looks like this:

现在 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    |            |
+--------+--------------+------+-----+---------+------------+

which is not quite what I want. As you can see

这不是我想要的。如你看到的

  1. float is not nullable,
  2. the type "url" turned out to as a blob rather than a varchar and
  3. mydate as "date" rather than "datetime"
  1. float 不可为空,
  2. 类型“url”结果是一个 blob 而不是 varchar 和
  3. mydate 为“日期”而不是“日期时间”

采纳答案by Ta Sas

Again thanks for your great support and suggestions. Actually, I have found the solution now. As Pascal mentioned, I had been using both, annotation driven and xml configuration mixed up. As soon as I deleted the xml config, this issue was solved.

再次感谢您的大力支持和建议。实际上,我现在已经找到了解决方案。正如 Pascal 所提到的,我一直在混合使用注释驱动和 xml 配置。一旦我删除了 xml 配置,这个问题就解决了。

I will not open an bug at hibernate, because it is best practice anyway not to mix up configuration types, hence, I would rather give the advice to carry out best practice than to mix up config types.

我不会在休眠时打开错误,因为无论如何最好不要混合配置类型,因此,我宁愿给出执行最佳实践的建议,而不是混合配置类型。

Cheers ER

干杯急诊室

回答by Pascal Thivent

float is not nullable,

float 不可为空,

This one is weird. nullableis used onlyas a column property for table creation and should do its job whether the mapped property is a primitive or not. At least your code works for me with Derby, I get a nullable column for the generated table. But obviously, using the wrapper (i.e. Float) at the object level would make sense if you want to be able to "pass" a nullvalue.

这个很奇怪。nullable使用作为列属性表的建立和应做的工作对应的属性是否是一种原始的或没有。至少您的代码适用于 Derby,我为生成的表获得了一个可为空的列。但显然,Float如果您希望能够“传递”一个null值,那么在对象级别使用包装器(即)是有意义的。

the type "url" turned out to as a blob rather than a varchar and

类型“url”结果是一个 blob 而不是 varchar 和

From the JPA 1.0 specification:

来自 JPA 1.0 规范:

2.1.1 Persistent Fields and Properties

...

The persistent fields or properties of an entity may be of the following types: Java primitive types; java.lang.String; other Java serializable types (including wrappers of the primitive types, java.math.BigInteger, java.math.BigDecimal, java.util.Date, java.util.Calendar, java.sql.Date, java.sql.Time, java.sql.Timestamp, user-defined serializable types, byte[], Byte[], char[], and Character[]); enums; entity types and/or collections of entity types; and embeddable classes (see section 2.1.5).

2.1.1 持久字段和属性

...

实体的持久字段或属性可以是以下类型: Java 原始类型;java.lang.String; 其他 Java 可序列化类型(包括原始类型的包装器、 、java.math.BigIntegerjava.math.BigDecimaljava.util.Datejava.util.Calendarjava.sql.Datejava.sql.Timejava.sql.Timestamp、用户定义的可序列化类型byte[]Byte[]char[]、 和Character[]);枚举;实体类型和/或实体类型的集合;和可嵌入的类(参见第 2.1.5 节)。

The java.net.URLis serializable, that's all (from a JPA point of view), so it gets treated as serializable (and stored in a BLOB).

java.net.URL序列化,这是所有(从一个JPA点),所以它得到处理序列化(并存储在BLOB)。

If you really want it to be stored as a String, either use a custom UserType(Hibernate specific) or use a Stringholder and provide getter/setter doing a conversion (and mark the getter as Transient). Something like this:

如果您真的希望将其存储为String,请使用自定义UserType(特定于 Hibernate)或使用String持有者并提供 getter/setter 进行转换(并将 getter 标记为 Transient)。像这样的东西:

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;
}

mydate as "date" rather than "datetime"

mydate 为“日期”而不是“日期时间”

If you want to alsostore the time part of your date, map it as a timestamp using the @Temporalannotation:

如果你想存储您的日期的时间部分,其对应为使用时间戳@Temporal注释:

@Column(nullable = true)
@Temporal(TemporalType.TIMESTAMP)
private Date myDate;

PS: By the way, why do you provide both annotations AND an orm.xml? Are you aware that they are somehow equivalent? If you can use annotations, just use them, no need for that orm.xml.

PS:顺便说一句,你为什么同时提供注释和一个orm.xml?你知道它们在某种程度上是等价的吗?如果您可以使用注释,只需使用它们,不需要那个orm.xml

回答by duffymo

A float primitive isn't nullable, but a java.lang.Float or java.lang.Double is.

浮点原语不可为空,但 java.lang.Float 或 java.lang.Double 可以。

If that doesn't work, maybe you need to think more abstractly. What does that float represent? A "number" isn't very descriptive. Is it an account balance? Something else that's meaningful for your problem? If yes, wrap it in an object that describes and abstracts it better.

如果那不起作用,也许您需要更抽象地思考。那个浮标代表什么?“数字”不是很具有描述性。是账户余额吗?还有什么对你的问题有意义的吗?如果是,请将其包装在一个可以更好地描述和抽象它的对象中。

Java's an object-oriented language, and the "O" in ORM stands for objects. Think less in terms of primitives and relational columns and more in terms of objects. You'll find Hibernate easier if you do so.

Java 是一种面向对象的语言,ORM 中的“O”代表对象。少考虑原语和关系列,多考虑对象。如果这样做,您会发现 Hibernate 更容易。