Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Optional query parameters for Android Room

I have the following DAO with a query:

@Dao
public interface BaseballCardDao {
    @Query(
        "SELECT * FROM baseball_cards " +
        "WHERE brand LIKE :brand " +
        "  AND year = :year " +
        "  AND number LIKE :number " +
        "  AND player_name LIKE :playerName " +
        "  AND team LIKE :team"
    )
    LiveData<List<BaseballCard>> getBaseballCards(
        String brand, int year, String number, String playerName, String team
    );
}

The String parameters are "optional" in the sense that I can pass "%%" to match all rows due to the LIKE operator. But I cannot do this with year since it is an int. One solution is to add two different @Query methods, one with the int year parameter and the other without. Is there a more elegant way to create an optional parameter with Room's @Query?

like image 911
Code-Apprentice Avatar asked Aug 26 '18 19:08

Code-Apprentice


People also ask

Can query parameters be optional?

As query parameters are not a fixed part of a path, they can be optional and can have default values.

How to write query in android studio?

You can write a query like this: @Query("SELECT last_name, name FROM user WHERE uid = :userId LIMIT 1") public abstract UserName findOneUserName(int userId); And Room will create the correct implementation to convert the query result into a UserName object.

What are the components of room database in Android?

While developing an app with Room, we need to implement all of three main components: Entity, Dao, Database.

Does room return null?

But what we realised was that Room does not do a good job in handling null safety errors as the Kapt for Room is not written in Kotlin. Because of that, it doesn't know whether the type we set it is a nullable or non-null to throw compilation warnings. And instead, it returns null for every possible value.


1 Answers

It is a late answer but as I have faced it recently, I wanted to share my simple (but silly!) trick for those who are looking for it.

As @CommonsWare has said, we can add an OR statement that checks for null to it and then simply make our optional parameters nullable and pass null for them. For example, your query would look like:

@Dao
public interface BaseballCardDao {
    @Query(
        "SELECT * FROM baseball_cards " +
        "WHERE (:brand IS NULL OR brand LIKE :brand)" +
        "  AND (:year IS NULL OR year = :year)" +
        "  AND (:number IS NULL OR number LIKE :number)" +
        "  AND (:playerName IS NULL OR player_name LIKE :playerName)" +
        "  AND (:team IS NULL OR team LIKE :team)"
    )
    LiveData<List<BaseballCard>> getBaseballCards(
        @Nullable String brand, @Nullable Integer year, @Nullable String number, @Nullable String playerName, @Nullable String team
    );
}

Or more declarative using kotlin and optional parameters:

@Query(
    """SELECT * FROM baseball_cards 
        WHERE (:brand IS NULL OR brand LIKE :brand) 
        AND (:year IS NULL OR year = :year) 
        AND (:number IS NULL OR number LIKE :number) 
        AND (:playerName IS NULL OR player_name LIKE :playerName)
        AND (:team IS NULL OR team LIKE :team)"""
)
fun getBaseballCards(
    brand: String? = null,
    year: Int? = null,
    number: String? = null,
    playerName: String? = null,
    team: String? = null
): LiveData<List<BaseballCard>>

Edit: Please consider that this solution is useful for non-nullable fields. If the field is nullable and you want to look for the records which don't have a value for the field, this is not the correct way of querying and you may consider dynamic query creation.

like image 189
momt99 Avatar answered Oct 18 '22 03:10

momt99