如何使用 Android Room Persistence Library 将 Column 注释为 NOT NULL

Posted

技术标签:

【中文标题】如何使用 Android Room Persistence Library 将 Column 注释为 NOT NULL【英文标题】:How to annotate Column as NOT NULL using Android Room Persistence Library 【发布时间】:2017-11-08 18:20:41 【问题描述】:

我的数据类是这样的

@Entity(tableName = "items")
data class Item(
        @ColumnInfo(name = "name") var name: String = "",
        @ColumnInfo(name = "room") var room: String = "",
        @ColumnInfo(name = "quantity") var quantity: String = "",
        @ColumnInfo(name = "description") var description: String = "",
        @PrimaryKey(autoGenerate = true)
        @ColumnInfo(name = "id") var id: Long = 0
)

Room 使用 SQLite,并且 SQLite 在其数据库中支持 NOT NULL 列。我尝试使用 @NonNull 注释列,但没有效果。

有没有办法使房间数据库中的列不能为空?

【问题讨论】:

默认不是not null?因为我也在研究房间持久性库,并且不小心将 null 发送到数据库,所以它触发了异常。 我得到了一些空字段,比如空字符串,它工作正常,所以我猜不是这样 那你的问题是什么? 【参考方案1】:

对于 Java,您应该使用 @android.support.annotation.NonNull 进行注释

不要与@io.reactivex.annotations.NonNull混淆

【讨论】:

你拯救了我的一天! 如果我们需要将 RxJava 与 Room 一起使用,那么在创建实体时我们应该导入哪个? Ishwor Khanal,同样的@android.support.annotation.NonNull,rx 的注解主要用于内部目的【参考方案2】:

为了确定 NOT NULL 的确切注释,我查看了此链接提供的所有注释列表:android.arch.persistence.room,但找不到任何相关注释:

我的假设是,由于您使用的是 Kotlin,它默认将 var 视为非可选的,因此您声明的所有属性都不是 NULL。为了将 var 声明为可选,您可能必须使用 ?运算符,下面是一个例子:

var name: String // NOT NULL 
var name: String? // OPTIONAL

根据评论更新:

我猜你对 NULL 和空字符串感到困惑。 NULL 表示没有值,在共享代码中,您为每个列提供了一个默认值,该列是一个空字符串并且不等于 NULL,因此即使您可能没有为该属性提供值,它默认分配一个给它的空字符串。

尝试删除属性的赋值运算符和 RHS 值,然后插入记录而不为该属性赋值,您应该会得到相应的错误。

基本上,转换下面的语句:

@ColumnInfo(name = "name") var name: String = ""

@ColumnInfo(name = "name") var name: String

【讨论】:

我对数据库中 NOT NULL 的理解意味着它不能是空字段,它需要分配一个值,以便将空字符串 "" 视为 NULL。在 kotlin 中,字符串意味着它分配的对象不为空,在我的情况下默认为空字符串。我只希望我的数据库在分配空字符串时抛出异常。我猜你不能在房间里这样做 我会将其标记为正确,因为它澄清了我在空字符串和 null 之间的混淆。但是,在我的特殊情况下,您建议的转换语句(第二个)不可编译,因为 Room 需要默认构造函数,并且为此每个参数都必须具有默认值。但是感谢您的帮助! 谢谢,最初,这个答案对我不起作用,因为我将变量的范围设置为 private 谢谢。使用NonNull 注释+ 设置没有赋值的属性也为我解决了这个问题@Devarshi "它需要分配一个值,以便空字符串 "" 将被视为 NULL" 这是不正确的。空字符串不为空。空为空。空字符串是长度为 0 的字符串对象。【参考方案3】:

对于 Java,我在 @ColumnInfo 之后使用了 @NonNull

@ColumnInfo(name = "column_name")
@NonNull private String str;

确保您在类中导入了正确的库:

import android.support.annotation.NonNull;

【讨论】:

请注意,原始类型(int、long 等)总是被认为是 NonNull,您不必像这样对它们进行注释。 @BeerMe,你知道它记录在哪里吗?我刚刚在this article 中发现了对原始类型管理的提及。似乎浮点类型的处理方式不同,默认情况下可以为空。 @shield,我手边没有实际的文档,但这个答案总结得很好:***.com/a/11047335/295028 另外,我在您的链接文章中没有看到任何对浮点类型的引用,但它确实说“所有原始类型在 Room 中默认为非 null”。 @BeerMe,谢谢。我关于浮点类型的错误。在我查看的示例中,列类型不是原始的。它被声明为浮点数,而不是浮点数,因此默认情况下可以为空。【参考方案4】:

对使用 Kotlin 的人的补充回答:

请注意,将类型标记为非可选会自动使其不为空(可选类型不会这样做)。

您可以在数据库中使用@Database(exportSchema = true) 生成的架构中检查它。

例如我有这样的事情:

@Entity(tableName = "messages")
data class Message (
        @PrimaryKey
        val messageId: UUID = UUID.randomUUID(),
        val date: Date = Date(),
        val receivedDate: Date? = null
)

在生成的架构中我可以阅读:

"CREATE TABLE IF NOT EXISTS `$TABLE_NAME` (
    `messageId` TEXT NOT NULL, 
    `date` INTEGER NOT NULL, 
    `receivedDate` INTEGER, 
    PRIMARY KEY(`messageId`)
)"

(注意:这里的日期类型是Int,UUID 是字符串,因为我在其他地方使用了转换器)

【讨论】:

【参考方案5】:

作为实际表约束的变通方法,您可以使用单个方法 TypeConverter 类来确保您的 String 成员不为空。

例如,对于非空字符串,您可以使用:

public class RoomConverterNullString 
    @TypeConverter
    public static String fromNullToString(String value) 
        if (value == null) 
            return "";
         else 
            return value;
        
    

当然可以这样简化:

public class RoomConverterNullString 
    @TypeConverter
    public static String fromNullToString(String value) 
        return (value == null) ? "" : value;
    

你可以这样使用它:

@TypeConverters(RoomConverterNullString.class)
public String stringMember;

当值为空时,任何赋值和更新/插入操作都将存储一个空字符串值,并且任何检索都会强制将空值转换为空字符串。

您可以对其他类型以及您希望拥有的任何默认值执行此操作。

【讨论】:

以上是关于如何使用 Android Room Persistence Library 将 Column 注释为 NOT NULL的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Android Room 从数据库中获取一行? [复制]

如何在android中使用Room Library fts4查询整个表

Android:如何使 Kotlin 中所有对象列表的类型转换器(用于 Room)通用

使用带有 Android 的 Room 使用 UUID 作为主键

如何将带有 Android Room 的应用添加为使用 makefile 编译的系统应用?

如何使用 Android Room Persistence Library 将 Column 注释为 NOT NULL