1

When you use Android Room auto generated insert method, it pass all values to all columns For example, if you have an entity like below:

@Entity
public class Task {

    @PrimaryKey(autoGenerate = true)
    public long id;

    @NonNull
    @ColumnInfo(defaultValue = "Unknown Title")
    public String name;

    @NonNull
    @ColumnInfo(defaultValue = "Does not have any description!")
    public String desc;

    @ColumnInfo(defaultValue = "false")
    public boolean isDone;
}

And you try to insert an empty instance of Task class by:

taskDao.insert(new Task());

It will run a query like this:

INSERT INTO Task (id, name, desc, isDone) values (null, null, null, 0);

that is against of our table structure rules, so we get error:

Caused by: android.database.sqlite.SQLiteConstraintException: NOT NULL constraint failed: task.name (code 1299 SQLITE_CONSTRAINT_NOTNULL)

While if it use this query:

INSERT INTO Task DEFAULT VALUES;

or

INSERT INTO Task (id) VALUES (null);

SQLite creates a row with all default values, without any errors.

But to ignore null variables in the insert query for using default valuse?

golkarm
  • 1,021
  • 1
  • 11
  • 22
  • why don't you do this: mName="Unknown title" – Sami Shorman Mar 10 '21 at 11:27
  • I will use the default values but with room it passes null to database, instead of ignoring it – golkarm Mar 10 '21 at 11:31
  • i don't get what u mean but if u remove the default value from **ColoumnInfo** and pass your default value as a value for the attribute then room will set this default value if the user miss any value u want. – Sami Shorman Mar 10 '21 at 11:46
  • You right but what you said sets a value that will passed to database, but value of default column in ColumnInfo will use when where are not a passed value like this query `INSERT INTO TABLE task (name) values ("my task");` that ignores id, description and is_done columns – golkarm Mar 10 '21 at 11:57
  • I update my question completely – golkarm Mar 10 '21 at 13:44

2 Answers2

0

Try this:

@Entity
public class Task {
    public String mName = "Unknown Title";
    public String mDescription = "Does not have any description!";
    public boolean mIsDone  = "false";

    @PrimaryKey(autoGenerate = true)    //must be placed at the end!!
    public long id = 0;
}

And create object like this:

Task task = new Task()    //all use default values

Task task = new Task(name)    //use default values for other fileds

Task task = new Task(name, description)    //the order matters, otherwise you need to explicitlty specify the filed, like following

Task task = new Task(mIsDone = true, mName = "Sam")

Sam Chen
  • 7,597
  • 2
  • 40
  • 73
  • why id must be placed at the end?? – golkarm Mar 10 '21 at 15:03
  • @Mohammad7G https://stackoverflow.com/questions/64517656/android-room-database-create-entity-object-without-id – Sam Chen Mar 10 '21 at 15:16
  • @Mohammad7G Does it help? – Sam Chen Mar 11 '21 at 03:44
  • about of 1st part of your answer, pay attention to my question, I explained that it passes null. and in part 2 seems that Room doesn't handle my ask directly – golkarm Mar 11 '21 at 05:50
  • @Mohammad7G You got null because you didn't give the default value to that field man, `columnInfo(defaultValue)` does not work the way you expect, it's for migration use: https://developer.android.com/training/data-storage/room/migrating-db-versions#handle-default-values-migrations. Just give it a try. – Sam Chen Mar 11 '21 at 11:49
0

Based on what is written in the Android documentation:

The default value you specify here will NOT be used if you simply insert the Entity with @Insert.

That means there are no simple way but you can do it in some ways:

  1. Assign Variables Values

Assign what you defined as default values in @ColumnInfo, for those variables value, because if you doesn't update those values, the default assignment will be used, as Documentation says:

If you simply insert the Entity with @Insert ... any value assigned in Java/Kotlin will be used.

@Entity
public class Task {

    @PrimaryKey(autoGenerate = true)
    public long id;

    @NonNull
    @ColumnInfo(defaultValue = "Unknown Title")
    public String name = "Unknown Title";

    @NonNull
    @ColumnInfo(defaultValue = "Does not have any description!")
    public String description = "Does not have any description!";

    @ColumnInfo(defaultValue = "false")
    public boolean isDone; // it doesn't need assignment
                           // boolean values are false as default
}
  1. Special Query

As Documentation recommend:

Use @Query with an INSERT statement and skip this column there in order to use this default value.

@Query("INSERT INTO task DEFAULT VALUES")
long insert();

or

@Query("INSERT INTO task (id) VALUES (null)")
long insert();

As you told in your question.

  1. Simplified Class (ref)
@Insert(entity = Task.class)
long insert(NewTask task);

@Entity
class NewTask {
    int id = 0;
}

it runs

INSERT INTO task (id) VALUES (null);
golkarm
  • 1,021
  • 1
  • 11
  • 22