32

My data class looks like this

@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 uses SQLite and SQLite supports NOT NULL columns in its database. I tried annotating columns with @NonNull but it has no effect.

Is there a way to make columns in Room Database not nullable?

Tuby
  • 3,158
  • 2
  • 17
  • 36

5 Answers5

45

For Java you should annotate with @android.support.annotation.NonNull

DO NOT CONFUSE WITH @io.reactivex.annotations.NonNull

Boken
  • 4,825
  • 10
  • 32
  • 42
Nokuap
  • 2,289
  • 2
  • 17
  • 17
32

In order to identify exact annotation for NOT NULL I went through the list of all annotations provided at this link: android.arch.persistence.room but could not find any relevant annotation:

enter image description here

My assumption is that since you are using Kotlin, which by default treats a var as non-optional, all the attributes declared by you are NOT NULL. In order to declare a var as optional probably you have to use a ? operator, an example below:

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

Updated based on comment:

I guess you are confused with NULL and empty string. NULL means no value, in the shared code you are providing a default value to each column which is an empty string and that is not equal to NULL, so even though you might not have provided a value for that attribute it is by default assigning an empty string to it.

Try removing value assignment operator and RHS value for an attribute and then insert the record without assigning value to that attribute, you should get appropriate error.

Basically, convert below statement:

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

To

@ColumnInfo(name = "name") var name: String
Devarshi
  • 16,440
  • 13
  • 72
  • 125
  • My understanding of what NOT NULL in database means it cannot be empty field, it needs to have a value assigned so that empty string "" would be considered NULL. In kotlin String means it has object assigned that is not null, empty string by default in my case. I just want my database to throw exception when it is assigned empty string. I guess you can't do that in Room – Tuby Jun 07 '17 at 21:06
  • I will mark it as correct because it clarified my confusion between empty string and null. However in my particular case your proposed converted statement(second one) is not compilable because Room requires default constructor, and to do so each parameter has to have default value. But thanks for help! – Tuby Jun 08 '17 at 08:26
  • Thanks, initially, this answer wasn't working for me because I had the scope set to `private` on the variable. – olfek Nov 24 '18 at 11:54
  • 1
    Thanks. with `NonNull` annotation + set the properties without assignment fixed the issue for me as well @Devarshi – mochadwi Feb 18 '19 at 02:42
  • "it needs to have a value assigned so that empty string "" would be considered NULL" That is not correct. An empty string is not null. Null is null. Empty string is a string object of length 0. – user1713450 Feb 14 '20 at 15:22
12

For Java I used @NonNull after the @ColumnInfo:

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

Ensure that you have imported the correct library in the class:

import android.support.annotation.NonNull;
Awsom3D
  • 920
  • 7
  • 22
avisper
  • 878
  • 12
  • 11
  • 4
    Note that primitive types (int, long, etc) are _always_ considered to be NonNull, and you don't have to annotate them as such. – Beer Me Jan 20 '19 at 22:48
  • @BeerMe, do you know where it is documented? I just found a mention of the management of the primitive types in [this article](https://medium.com/@iamsadesh/moving-to-room-310b19c83cf4). It seems that float types are not treated the same and are nullable by default. – shield Sep 22 '20 at 15:08
  • @shield, I don't have the actual documentation handy, but this answer sums it up pretty well: https://stackoverflow.com/a/11047335/295028 – Beer Me Sep 22 '20 at 19:48
  • Also, I don't see any reference to float types in your linked article, but it does say "All the primitive types are by default non null in Room". – Beer Me Sep 22 '20 at 19:49
  • 1
    @BeerMe, thanks. My mistake regarding the float type. In the example I looked at, the column type was not primitive. It was declared as Float, not float, and was therefore nullable by default. – shield Sep 23 '20 at 08:23
11

Complementary answer for those using Kotlin:

please note that marking a type as non optional will automatically make it not null (and an optional type will not do that).

You can check it in the schema generated by room with @Database(exportSchema = true) on your database.

For example I have something like that:

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

And in the generated schema I can read:

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

(Note: the Date type is here an Int and the UUID a string due to converters I use elsewhere)

JJD
  • 50,076
  • 60
  • 203
  • 339
Vincent Hiribarren
  • 5,254
  • 2
  • 41
  • 65
5

As a work around to actual table constraints, you could use a single method TypeConverter class to make sure your String members are not null.

For example, for a Non-null String, you could use:

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

You can simplify it like this, of course:

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

And you can use it like this:

@TypeConverters(RoomConverterNullString.class)
public String stringMember;

Any assignments and update/insert actions will store an empty string value when the value is null and any retrieval will force a null value to be converted to an empty string.

You can do this for other types and for any default values you wish to have.

Evan I
  • 81
  • 1
  • 4