Search code examples
androidandroid-sqliteandroid-roomentityandroid-database

Android Room additional constructor parameter


I have an entity looking as follows:

@Entity(tableName = "my_table")
public class MyEntity {

    @PrimaryKey(autoGenerate = true)
    @ColumnInfo
    private final Integer id;

    @ColumnInfo
    private final String data;

    @Ignore
    private final boolean bool;

    public MyEntity(Integer id, String data) {
        this.id = id;
        this.data = data;
        this.bool= false;
    }

    public MyEntity(Integer id, String data, boolean bool) {
        this.id = id;
        this.data = data;
        this.bool = bool;
    }

    // getters...
}

And the corresponding DAO:

@Dao
public interface MyDao {
    @Query("SELECT id, data, 1 FROM my_table WHERE id = :id")
    LiveData<MyEntity> getById(int id);
}

When i call getById(int), only the first constructor without bool is being used and the returned MyEntity always has bool = false. It seems like the 1 in the query is completely ignored.

How can i make it so the DAO uses the other constructor which includes bool (and therefore sets bool = true)?


Solution

  • It seems like the 1 in the query is completely ignored.

    And that is what you have specified. As far as Room is concerned the bool column is superfluous and will be ignored if building a MyEntity. Hence the warning like:-

    warning: The query returns some columns [bool] which are not used by MyEntity. You can use @ColumnInfo annotation on the fields to specify the mapping. You can annotate the method with @RewriteQueriesToDropUnusedColumns to direct Room to rewrite your query to avoid fetching unused columns.  You can suppress this warning by annotating the method with @SuppressWarnings(RoomWarnings.CURSOR_MISMATCH). Columns returned by the query: id, data, bool.
    LiveData<MyEntity> getById(int id);
    

    Now if you were to have a POJO, for example:-

    class MyClassWithBool {
        Integer id;
        String data;
        boolean bool;
    
        public String getData() {
            return data;
        }
    
        public Integer getId() {
            return id;
        }
    
        public boolean isBool() {
            return bool;
        }
    
        public MyEntity getAsMyEntity() {
            return new MyEntity(id,data,bool);
        }
    }
    

    Then room will be able to assign the additional column BUT only if you return the POJO. e.g. you could then have:-

    @Dao
    public interface MyDao {
        @Query("SELECT id, data/*, 1*/ FROM my_table WHERE id = :id")
        LiveData<MyEntity> getById(int id);
        @Query("SELECT id, data, 1 AS bool FROM my_table WHERE id=:id")
        LiveData<MyClassWithBool> getByIdWithBool(int id);
    }
    
    • note that the 3rd output column has been commented out in the first to supress the warning issued in the build.
    • the getAsMyEntity method will return a MyEntity from the MyClassWithBool

    The assumption is that the far simpler:-

    public MyEntity(Integer id, String data) {
        this.id = id;
        this.data = data;
        this.bool= true;
    }
    

    would not suit (in which the 3rd column is also superfluous)

    In short, if you want anything other than the Entity extracted, then you need to specify a suitable class (or type in the case of a single value) rathe than the Entity class.

    Furthermore Room expects the name of the output columns to match the member names (except in the case of a single value when it only has a 1-1 mapping between column and where to place the value). Hence the use of AS to give the column a name.