327

I am creating an Entity (Room Persistence Library) class Food, where I want to make foodId as autoincrement.

@Entity
class Food(var foodName: String, var foodDesc: String, var protein: Double, var carbs: Double, var fat: Double)
{
    @PrimaryKey
    var foodId: Int = 0
    var calories: Double = 0.toDouble()
}

How can I set foodId an autoincrement field?

iknow
  • 8,358
  • 12
  • 41
  • 68
Sachin Chandil
  • 17,133
  • 8
  • 47
  • 65
  • 6
    Instead of `0.toDouble()` you can use `0.0` do declare it as a double – RobCo May 22 '17 at 15:57
  • 3
    How you create a new instance of Food class? Do you specify manually ID or you leave it blank? – Zookey Jun 24 '17 at 08:52
  • 29
    A note for future readers - the primary key must be 0 for Room to treat it as unset. If you use any other default value (e.g. -1), Room will not autogenerate the id. – Martin Melka Apr 05 '20 at 12:44

9 Answers9

547

You need to use the autoGenerate property

Your primary key annotation should be like this:

@PrimaryKey(autoGenerate = true)

Reference for PrimaryKey.

MatPag
  • 41,742
  • 14
  • 105
  • 114
  • 3
    Thanks, i was searching for autoIncrement, thats why wasn't able to find. – Sachin Chandil May 22 '17 at 09:59
  • Hey @MatPag what if i want two Primary keys in one table (Composite primary keys) and one of the primary key should be auto incremented? How can i achieve that? Can you answer this [here](https://stackoverflow.com/questions/46790830/how-to-make-primary-key-auto-increment-while-using-composite-primary-keys-in-roo) ? – Priyanka Alachiya Oct 18 '17 at 05:25
  • 2
    @MatPeg What in case if I want to have one PrimaryKey the is self-generated, and one that come from REST `@Entity( primaryKeys = arrayOf(COLUMN_ID_LOCAL,COLUMN_ID_REMOTE))` ? – murt Jan 18 '18 at 15:08
  • @murt You need a composite primary key, but you can't do what you want to achieve. Read [here](https://stackoverflow.com/a/46804610/2910520) – MatPag Jan 18 '18 at 15:20
  • Important part of the linked documentation: `Insert methods treat 0 as not-set while inserting the item. ` – Micha Mar 02 '20 at 13:41
203

You can add @PrimaryKey(autoGenerate = true) like this:

@Entity
data class Food(
        var foodName: String, 
        var foodDesc: String, 
        var protein: Double, 
        var carbs: Double, 
        var fat: Double
){
    @PrimaryKey(autoGenerate = true)
    var foodId: Int = 0 // or foodId: Int? = null
    var calories: Double = 0.toDouble()
}
Allan Veloso
  • 5,823
  • 1
  • 38
  • 36
  • 53
    `foodId` doesn't needs to be null (but it can be). One could also use default values eg. `var foodId: Int = 0` and the autogenerate would work properly. – Michał Pawlik Mar 01 '18 at 12:15
  • That's pretty unintuitive but I can't see how the Room devs could get around it – Daniel Wilson Apr 30 '18 at 17:23
  • What if I want to overwrite foodId - passing it as custom value to Entity? Does that cause it to not auto-increment? – IgorGanapolsky May 11 '18 at 19:59
  • @MichałBaran If you make it 0, does it still have to be a null-able int? – JMK Aug 11 '18 at 17:54
  • 11
    @MichałBaran, from the java doc, when the type is a primitive java ```int``` or ```long```, 0 is treat as null-able, when the type is Integer or Long, null is the nullable. Since Kotlin Int when non-nullable works in JVM as primitive int, then you are right and ```var foodId: Int = 0``` will work, but ```var foodId: Int? = 0``` will not work since Int? is converted in JVM as Integer. @JMK, if you make it 0, you HAVE to make a non-nullable ```int``` for the reason aforementioned. – Allan Veloso Aug 12 '18 at 21:41
  • 4
    You can write without in another way: `val jack = User(name = "Jack", phone= 1)` In this case you can remove 0 from constructor – Roman Soviak Nov 16 '18 at 10:13
  • 3
    The problem I see with this approach is in terms of it being a data class. When Food is a data class (like in the snippet), food is been used for the equals() comparison, so two foods with different foodId can be considered equal. Using named arguments with default values will solve the issue. – Sotti Feb 01 '19 at 07:31
  • For me, it was not working when I use Int. But when I set Long instead of Int, it worked. `@PrimaryKey(autoGenerate = true) var foodId: Long = 0` – Vijay Aug 17 '19 at 11:35
  • 2
    @AllanVeloso Can you explain why `foodId` was put in the body and not in the constructor? – Neeraj Sewani Oct 18 '19 at 11:59
  • 4
    @neer17 since the foodId will be autogenerated by Room at insertion, more likely there will be no use to have it in the constructor. – Allan Veloso Oct 28 '19 at 13:32
  • My Room database tests failed when the PrimaryKey was defined null. Probably better to make it 0 instead as this seems to properly autogenerate. – jsonV Sep 26 '20 at 10:01
  • We can add also @Transient, in front of or above "var foodId" in order not to make it serializable when using it with Gson. – Kreshnik Oct 12 '21 at 17:46
  • 1
    can anyone explain why a primary key would be nullable?!? – DarkOhms Jan 05 '23 at 18:19
71

add @PrimaryKey(autoGenerate = true)

@Entity
public class User {

    @PrimaryKey(autoGenerate = true)
    private int id;

    @ColumnInfo(name = "full_name")
    private String name;

    @ColumnInfo(name = "phone")
    private String phone;

    public User(){
    }

    //type-1
    public User(String name, String phone) {
        this.name = name;
        this.phone = phone;
    }

    //type-2
    public User(int id, String name, String phone) {
        this.id = id;
        this.name = name;
        this.phone = phone;
    }

}

while storing data

 //type-1
 db.userDao().InsertAll(new User(sName,sPhone)); 

 //type-2
 db.userDao().InsertAll(new User(0,sName,sPhone)); 

type-1

If you are not passing value for primary key, by default it will 0 or null.

type-2

Put null or zero for the id while creating object (my case user object)

If the field type is long or int (or its TypeConverter converts it to a long or int), Insert methods treat 0 as not-set while inserting the item.

If the field's type is Integer or Long (Object) (or its TypeConverter converts it to an Integer or a Long), Insert methods treat null as not-set while inserting the item.

kunal khedkar
  • 877
  • 8
  • 6
  • 1
    Can we pass custom id to Entity, even though it is set to autoGenerate? – IgorGanapolsky May 11 '18 at 20:00
  • 3
    @Igor Ganapolsky Yes, but entry will genrate with that custom id [ auto-increment will not work ] And if you pass same id again it will throw exception 'UNIQUE constraint failed' so you need pass always new id or make it [0 or null] and let auto-increment do this work for you. – kunal khedkar May 14 '18 at 04:24
  • 4
    Why are you even letting the user put the id in the constructor if you want to autogenerate? – hellcast May 18 '18 at 15:48
  • In Kotlin you can use data class and write: `val jack = User(name = "Jack", phone= 1)` In this case you can remove 0 from constructor – Roman Soviak Nov 16 '18 at 10:09
  • @hellcast If you don't include the id in the constructor (as I just learned the hard way) when you query the DB it won't assign the id field (it will just be whatever you initialize it with in the constructor) since I assume it calls the same constructor when populating the object's fields. – Ali Hirani May 16 '19 at 09:07
  • why to set the id as 0 even when set to autogenerate?? – Prajwal Waingankar Mar 08 '20 at 15:35
59

Its unbelievable after so many answers, but I did it little differently in the end. I don't like primary key to be nullable, I want to have it as first argument and also want to insert without defining it and also it should not be var.

@Entity(tableName = "employments")
data class Employment(
    @PrimaryKey(autoGenerate = true) val id: Long,
    @ColumnInfo(name = "code") val code: String,
    @ColumnInfo(name = "title") val name: String
){
    constructor(code: String, name: String) : this(0, code, name)
}
Renetik
  • 5,887
  • 1
  • 47
  • 66
  • 2
    Now, How you are calling this class Employee without passing id as a parameter? Please tell. – Jaimin Modi Mar 12 '21 at 06:21
  • 1
    @JaiminModi you see secondary constructor there ? yo can call it Employment(code = "code", name = "name") or simple Employment("code", "name") – Renetik Mar 14 '21 at 05:32
  • 10
    Creating an extra constructor isn't even necessary for this case. Just add the 0 as default parameter to the id and you will automatically be able to use the constructor without this extra declaration: @PrimaryKey(autoGenerate = true) val id: Long = 0L, – J. Hegg Mar 21 '21 at 12:12
  • It's not true that you will automatically be able to use the constructor without this extra declaration if you add default value as first parameter. You will have to use named arguments in that case what is mostly not desirable in my case, so that's why secondary constructor is needed here. – Renetik Mar 29 '21 at 00:37
  • I mean, using named arguments when constructing a class that takes so many Strings, Integers and Longs as parameters is probably the better approach. – Ahmed Mourad May 25 '21 at 23:04
  • Usually ```@Insert``` annotation in your DAO is marked with conflict resolution strategy which is often ``` ReplaceOnInsert```. When you put existing id in your new row and insert it, id would not be autogenerated, but the row would be replaced. You also could not leave it as nullable type because you will get runtime exception which claims a db schema requires non-nullable field. – Joe Dow Jan 10 '23 at 10:58
  • __UPDATE__: you can leave uid as 0, with zero uid key is autoincremented. Another possible option like -1 would insert it 'as is' – Joe Dow Jan 10 '23 at 14:12
28

This works for me:

@Entity(tableName = "note_table")
data class Note(
    @ColumnInfo(name="title") var title: String,
    @ColumnInfo(name="description") var description: String = "",
    @ColumnInfo(name="priority") var priority: Int,
    @PrimaryKey(autoGenerate = true) var id: Int = 0//last so that we don't have to pass an ID value or named arguments
)

Note that the id is last to avoid having to use named arguments when creating the entity, before inserting it into Room. Once it's been added to room, use the id when updating the entity.

Chris Sprague
  • 3,158
  • 33
  • 24
10
@Entity(tableName = "user")
data class User(

@PrimaryKey(autoGenerate = true)  var id: Int?,
       var name: String,
       var dob: String,
       var address: String,
       var gender: String
)
{
    constructor():this(null,
        "","","","")
}
  • 5
    While this code snippet may be the solution, [including an explanation](//meta.stackexchange.com/questions/114762/explaining-entirely-‌​code-based-answers) really helps to improve the quality of your post. Remember that you are answering the question for readers in the future, and those people might not know the reasons for your code suggestion. – Johan Jun 05 '19 at 06:31
  • 4
    There are many answers like "use `@PrimaryKey(autoGenerate = true)`" - does your answer add anything new to this thread? – barbsan Jun 05 '19 at 06:50
  • 1
    yes it adds - it presents how null covers the autogenearted field – Marian Paździoch Apr 15 '20 at 08:32
9

For example, if you have a users entity you want to store, with fields (firstname, lastname , email) and you want autogenerated id, you do this.

@Entity(tableName = "users")
data class Users(
   @PrimaryKey(autoGenerate = true)
   val id: Long,
   val firstname: String,
   val lastname: String,
   val email: String
)

Room will then autogenerate and auto-increment the id field.

Nicola Gallazzi
  • 7,897
  • 6
  • 45
  • 64
mayojava
  • 189
  • 3
  • 5
5

In the example below when you create a new user pass the parameters as is in the constructor. Room will autogenerate the id. All user object ids are already set to the int default in the id setter so don't call setId

@Entity
public class User {

    @PrimaryKey(autoGenerate = true)
    private int id;

    @ColumnInfo(name = "full_name")
    private String name;

    @ColumnInfo(name = "phone")
    private String phone;

   
    public User(String name, String phone) {
        this.name = name;
        this.phone = phone;
    }

    public void setId(int id){
        this.id = id;
    }

}
Linus Kiarie
  • 51
  • 1
  • 4
  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Jan 23 '22 at 00:06
2

Annotate your Entity class with the code below.

In Java:

@PrimaryKey(autoGenerate = true)
private int id;

In Kotlin:

@PrimaryKey(autoGenerate = true)
var id: Int

Room will then auto-generate and auto-increment the id field.

Community
  • 1
  • 1
Fakhriddin Abdullaev
  • 4,169
  • 2
  • 35
  • 37