如何在房间数据库 dao 中附加两个或多个子查询,而这些子查询存储在变量中

How to attach two or more sub queries in room database dao while those subQuery stored in variables

我正在将我的旧数据库升级到 room 数据库,同时从普通 sql 语句转换为 room sql 语句。 我面临以下情况的问题。

情景一: 我已经将子查询存储在这样的变量中

String subQueryLocalAddress = "SELECT * FROM localAddressTable where activeAddressId = 1";
String subQueryPermanentAddress = "SELECT * FROM permanentAddressTable where activeAddressId = 1";

现在,这将是有条件的,就像那样。

public Cursor loadAllUserAdress(boolean isLocal){
  String userAddressQuery = "SELECT * FROM userTable Where " 
        + isLocal? subQueryLocalAddress : subQueryPermanentAddress;
 
 SQLiteDatabase db = this.getReadableDatabase();
 Cursor cursor = db.rawQuery(userAddressQuery, null);
 
 return cursor;
}

场景二: 我有一堆像

这样的常量过滤器
Constant.ORDER_BY_FIRST_NAME_DESC = "ORDER BY firstName DESC";
Constant.ORDER_BY_LAST_NAME_DESC = "ORDER BY lastName DESC";

现在,此标志设置为 UI 级别,它将根据各自的标志检查数据库 class 我的查询将 return 尊重数据。

 public Cursor loadAllUserDetails(){
  String userDetailsQuery = "SELECT * FROM userTable Where " + Constant.ORDER_BY_LAST_NAME_DESC;
 
 SQLiteDatabase db = this.getReadableDatabase();
 Cursor cursor = db.rawQuery(userDetailsQuery, null);
 
 return cursor;
}

我想在单个变量中组合或合并两个或多个子查询,然后触发它。我有动态查询。

简而言之,使用@Rawquery注解进行动态查询。

演示

这是使用简单的 table TableX 和 id (long/INTEGER PRIMARY KEY)、名字 (String/TEXT) 和姓氏 (String/TEXT).

该演示插入一些数据,然后通过动态生成的排序提取数据SQL(场景二)。

在房间 TableX 嵌入 DBHelper 之前,其名称常量以及所有 ORDER BY 排列,还有一些方法 DBHelper :-

class DBHelper extends SQLiteOpenHelper {

    public static final String DBNAME = "mydb";
    public static final int DBVERSION = 1;
    private static volatile DBHelper instance = null;

    SQLiteDatabase db;

    private DBHelper(Context context) {
        super(context,DBNAME,null,DBVERSION);
        db = this.getWritableDatabase();
    }

    public static DBHelper getInstance(Context context) {
        if (instance == null) {
            instance = new DBHelper(context);
        }
        return instance;
    }


    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(TableX.createSQL);
        db.execSQL(TableX.createFirstNameIndex);
        db.execSQL(TableX.createLastNameIndex);

    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int i, int i1) {

    }

    public long insert(String firstName, String lastName) {
        ContentValues cv = new ContentValues();
        cv.put(TableX.COLUMN_FIRSTNAME,firstName);
        cv.put(TableX.COLUMN_LASTNAME,lastName);
        return db.insert(TableX.NAME,null,cv);
    }
    public Cursor loadAllDetails(int orderBy) {
        StringBuilder sb = new StringBuilder("SELECT * FROM ").append(NAME);
        switch (orderBy) {
            case TableX.FIRSTNAME_DESCENDING:
                sb.append(TableX.ORDER_BY_FIRSTNAME_DESC);
                break;
            case TableX.FIRSTNAME_ASCENDING:
                sb.append(TableX.ORDER_BY_FIRSTNAME_ASC);
                break;
            case TableX.LASTNAME_DESCENDING:
                sb.append(TableX.ORDER_BY_LASTNAME_DESC);
                break;
            case TableX.LASTNAME_ASCENDING:
                sb.append(TableX.ORDER_BY_LASTNAME_ASC);
                break;
            default:
                break;
        }
        sb.append(";");
        return db.rawQuery(sb.toString(),null);
    }

    class TableX {
        public static final String NAME = "tablex";
        public static final String COLUMN_ID = BaseColumns._ID;
        public static final String COLUMN_FIRSTNAME = "firstName";
        public static final String COLUMN_LASTNAME = "lastName";
        public static final String ORDER_BY_FIRSTNAME = " ORDER BY " + COLUMN_FIRSTNAME;
        public static final String ORDER_BY_LASTNAME = " ORDER BY " + COLUMN_LASTNAME;
        public static final String ORDER_BY_FIRSTNAME_DESC = ORDER_BY_FIRSTNAME + " DESC";
        public static final String ORDER_BY_FIRSTNAME_ASC = ORDER_BY_FIRSTNAME + " ASC";
        public static final String ORDER_BY_LASTNAME_DESC = ORDER_BY_LASTNAME + " DESC";
        public static final String ORDER_BY_LASTNAME_ASC = ORDER_BY_LASTNAME + " ASC";
        public static final int FIRSTNAME_DESCENDING = 0;
        public static final int FIRSTNAME_ASCENDING = 1;
        public static final int LASTNAME_DESCENDING = 2;
        public static final int LASTNAME_ASCENDING = 3;

        private static final String createSQL = "CREATE TABLE IF NOT EXISTS " + NAME + "(" +
                COLUMN_ID + " INTEGER PRIMARY KEY"
                + "," + COLUMN_FIRSTNAME + " TEXT"
                + "," + COLUMN_LASTNAME + " TEXT"
                + ")";
        private static final String createFirstNameIndex = "CREATE INDEX IF NOT EXISTS IDX_" + NAME + COLUMN_FIRSTNAME
                + " ON " + NAME + "("
                + COLUMN_FIRSTNAME
                + ")";
        private static final String createLastNameIndex = "CREATE INDEX IF NOT EXISTS IDX" + NAME + COLUMN_LASTNAME
                + " ON " + NAME + "("
                + COLUMN_LASTNAME
                + ")";

        public Cursor getSomeData(String query) {
            return db.rawQuery(query,null);
        }
    }
}

房间等价物

首先是@Entity class TableXEntity :-

@Entity(tableName = DBHelper.TableX.NAME,
        indices = {
                @Index(value = DBHelper.TableX.COLUMN_FIRSTNAME),
                @Index(value = DBHelper.TableX.COLUMN_LASTNAME)
        }
)
class TableXEntity {
    @PrimaryKey @ColumnInfo(name = DBHelper.TableX.COLUMN_ID)
    Long id;
    @ColumnInfo(name = DBHelper.TableX.COLUMN_FIRSTNAME)
    String firstName;
    @ColumnInfo(name = DBHelper.TableX.COLUMN_LASTNAME)
    String lastName;

    public TableXEntity(){}

    @Ignore
    public TableXEntity(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }
}
  • 冒昧使用预留空间常数
  • 除了@Ignored 第二个构造函数之外没有什么特别的

@Dao class TableXDao :-

@Dao
abstract class TableXDao {

    @Insert(onConflict = OnConflictStrategy.IGNORE)
    abstract long insert(TableXEntity tableXEntity);
    @Query("SELECT * FROM " + DBHelper.TableX.NAME + DBHelper.TableX.ORDER_BY_FIRSTNAME_ASC)
    abstract List<TableXEntity> getAllByFirstNameAscending();
    // etc

    /* cannot use the @Query below and commented out, as compile error
        error: extraneous input ':order' expecting
        {<EOF>, ';', K_ALTER, K_ANALYZE, K_ATTACH, K_BEGIN, K_COMMIT, K_CREATE, K_DELETE, K_DETACH,
        K_DROP, K_END, K_EXPLAIN, K_INSERT, K_PRAGMA, K_REINDEX, K_RELEASE, K_REPLACE, K_ROLLBACK, K_SAVEPOINT,
        K_SELECT, K_UPDATE, K_VACUUM, K_VALUES, K_WITH, UNEXPECTED_CHAR}
        abstract List<TableXEntity> getAllByPassedOrder(String order);

        Plus it wraps passed parameter in '' so is taken as a literal not an ORDER BY clause
     */
    //@SkipQueryVerification
    //@Query("SELECT * FROM " + DBHelper.TableX.NAME + " :order")
    //abstract List<TableXEntity> getAllByPassedOrder(String order);

    /* SO */
    @RawQuery
    abstract List<TableXEntity> rawq(SupportSQLiteQuery qry);
}
  • 请注意,假设它是 Room,因此没有 Cursors,而是对象数组。

The @Database class TheDatabase(注意不同的数据库名称,以便两者可以共存用于演示):-

@Database(entities = {TableXEntity.class},version = 1)
abstract class TheDatabase extends RoomDatabase {
    abstract TableXDao getTableXDao();

    private static volatile TheDatabase instance = null;

    public static TheDatabase getInstance(Context context) {
        if (instance == null) {
            instance = Room.databaseBuilder(
                    context, TheDatabase.class,"myroomdb"
            )
                    .allowMainThreadQueries()
                    .build();
        }
        return instance;
    }
}

将两者付诸行动是 MainActivity :-

public class MainActivity extends AppCompatActivity {

    DBHelper dbHelper;
    TheDatabase roomDB;
    TableXDao roomDao;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        dbHelper = DBHelper.getInstance(this);
        dbHelper.insert("Mary","Bloggs");
        dbHelper.insert("Francis","Frank");
        dbHelper.insert("Jane","Doe");
        logIt(dbHelper.loadAllDetails(DBHelper.TableX.LASTNAME_ASCENDING));
        logIt(dbHelper.loadAllDetails(DBHelper.TableX.FIRSTNAME_ASCENDING));
        logIt(dbHelper.loadAllDetails(DBHelper.TableX.LASTNAME_DESCENDING));

        /* Room */
        roomDB = TheDatabase.getInstance(this);
        roomDao = roomDB.getTableXDao();

        roomDao.insert(new TableXEntity("Mary","Bloggs"));
        roomDao.insert(new TableXEntity("Francis","Frank"));
        roomDao.insert(new TableXEntity("Jane","Doe"));

        roomLogit(roomDao.getAllByFirstNameAscending());
        roomLogit(getListByPassedOrder(DBHelper.TableX.FIRSTNAME_DESCENDING));
        roomLogit(getListByPassedOrder(DBHelper.TableX.FIRSTNAME_ASCENDING));
        roomLogit(getListByPassedOrder(DBHelper.TableX.LASTNAME_DESCENDING));
        roomLogit(getListByPassedOrder(DBHelper.TableX.LASTNAME_ASCENDING));

    }

    void logIt(Cursor c) {
        DatabaseUtils.dumpCursor(c);
    }

    void roomLogit(List<TableXEntity> thelist) {
        for (TableXEntity t: thelist) {
            Log.d("ROOMINFO","ID is " + t.id + " FirstName is " + t.firstName + " LastName is " + t.lastName);
        }
    }

    private List<TableXEntity> getListByPassedOrder(int order) {
        StringBuilder sb = new StringBuilder("SELECT * FROM ").append(DBHelper.TableX.NAME);
        switch (order) {
            case DBHelper.TableX.FIRSTNAME_DESCENDING:
                sb.append(DBHelper.TableX.ORDER_BY_FIRSTNAME_DESC);
                break;
            case DBHelper.TableX.FIRSTNAME_ASCENDING:
                sb.append(DBHelper.TableX.ORDER_BY_FIRSTNAME_ASC);
                break;
            case DBHelper.TableX.LASTNAME_DESCENDING:
                sb.append(DBHelper.TableX.ORDER_BY_LASTNAME_DESC);
                break;
            case DBHelper.TableX.LASTNAME_ASCENDING:
                sb.append(DBHelper.TableX.ORDER_BY_LASTNAME_ASC);
                break;
            default:
                break;
        }
        sb.append(";");
        return roomDao.rawq(new SimpleSQLiteQuery(sb.toString(),null));
    }
}
  • 首先填充预留数据库,使用各种动态生成的排序提取数据,并将 Cursor 转储到日志中。

  • 然后 room 数据库基本上模仿上面但显然使用 Room,数据到日志的输出虽然是通过提取的对象(TableXEntity 的)完成的。

日志中的结果:-

2021-09-22 13:08:19.393 I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@b9ccda0
2021-09-22 13:08:19.394 I/System.out: 0 {
2021-09-22 13:08:19.394 I/System.out:    _id=1
2021-09-22 13:08:19.394 I/System.out:    firstName=Mary
2021-09-22 13:08:19.394 I/System.out:    lastName=Bloggs
2021-09-22 13:08:19.394 I/System.out: }
2021-09-22 13:08:19.394 I/System.out: 1 {
2021-09-22 13:08:19.394 I/System.out:    _id=3
2021-09-22 13:08:19.394 I/System.out:    firstName=Jane
2021-09-22 13:08:19.394 I/System.out:    lastName=Doe
2021-09-22 13:08:19.395 I/System.out: }
2021-09-22 13:08:19.395 I/System.out: 2 {
2021-09-22 13:08:19.395 I/System.out:    _id=2
2021-09-22 13:08:19.395 I/System.out:    firstName=Francis
2021-09-22 13:08:19.395 I/System.out:    lastName=Frank
2021-09-22 13:08:19.395 I/System.out: }
2021-09-22 13:08:19.395 I/System.out: <<<<<


2021-09-22 13:08:19.396 I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@22a7d59
2021-09-22 13:08:19.396 I/System.out: 0 {
2021-09-22 13:08:19.396 I/System.out:    _id=2
2021-09-22 13:08:19.396 I/System.out:    firstName=Francis
2021-09-22 13:08:19.397 I/System.out:    lastName=Frank
2021-09-22 13:08:19.397 I/System.out: }
2021-09-22 13:08:19.397 I/System.out: 1 {
2021-09-22 13:08:19.397 I/System.out:    _id=3
2021-09-22 13:08:19.397 I/System.out:    firstName=Jane
2021-09-22 13:08:19.397 I/System.out:    lastName=Doe
2021-09-22 13:08:19.398 I/System.out: }
2021-09-22 13:08:19.398 I/System.out: 2 {
2021-09-22 13:08:19.398 I/System.out:    _id=1
2021-09-22 13:08:19.398 I/System.out:    firstName=Mary
2021-09-22 13:08:19.398 I/System.out:    lastName=Bloggs
2021-09-22 13:08:19.398 I/System.out: }
2021-09-22 13:08:19.398 I/System.out: <<<<<


2021-09-22 13:08:19.398 I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@a1ead1e
2021-09-22 13:08:19.399 I/System.out: 0 {
2021-09-22 13:08:19.399 I/System.out:    _id=2
2021-09-22 13:08:19.399 I/System.out:    firstName=Francis
2021-09-22 13:08:19.399 I/System.out:    lastName=Frank
2021-09-22 13:08:19.399 I/System.out: }
2021-09-22 13:08:19.399 I/System.out: 1 {
2021-09-22 13:08:19.399 I/System.out:    _id=3
2021-09-22 13:08:19.399 I/System.out:    firstName=Jane
2021-09-22 13:08:19.400 I/System.out:    lastName=Doe
2021-09-22 13:08:19.400 I/System.out: }
2021-09-22 13:08:19.400 I/System.out: 2 {
2021-09-22 13:08:19.400 I/System.out:    _id=1
2021-09-22 13:08:19.400 I/System.out:    firstName=Mary
2021-09-22 13:08:19.400 I/System.out:    lastName=Bloggs
2021-09-22 13:08:19.400 I/System.out: }
2021-09-22 13:08:19.400 I/System.out: <<<<<


2021-09-22 13:08:19.456 D/ROOMINFO: ID is 2 FirstName is Francis LastName is Frank
2021-09-22 13:08:19.456 D/ROOMINFO: ID is 3 FirstName is Jane LastName is Doe
2021-09-22 13:08:19.456 D/ROOMINFO: ID is 1 FirstName is Mary LastName is Bloggs


2021-09-22 13:08:19.458 D/ROOMINFO: ID is 1 FirstName is Mary LastName is Bloggs
2021-09-22 13:08:19.458 D/ROOMINFO: ID is 3 FirstName is Jane LastName is Doe
2021-09-22 13:08:19.458 D/ROOMINFO: ID is 2 FirstName is Francis LastName is Frank


2021-09-22 13:08:19.460 D/ROOMINFO: ID is 2 FirstName is Francis LastName is Frank
2021-09-22 13:08:19.460 D/ROOMINFO: ID is 3 FirstName is Jane LastName is Doe
2021-09-22 13:08:19.460 D/ROOMINFO: ID is 1 FirstName is Mary LastName is Bloggs


2021-09-22 13:08:19.462 D/ROOMINFO: ID is 2 FirstName is Francis LastName is Frank
2021-09-22 13:08:19.462 D/ROOMINFO: ID is 3 FirstName is Jane LastName is Doe
2021-09-22 13:08:19.462 D/ROOMINFO: ID is 1 FirstName is Mary LastName is Bloggs


2021-09-22 13:08:19.463 D/ROOMINFO: ID is 1 FirstName is Mary LastName is Bloggs
2021-09-22 13:08:19.463 D/ROOMINFO: ID is 3 FirstName is Jane LastName is Doe
2021-09-22 13:08:19.463 D/ROOMINFO: ID is 2 FirstName is Francis LastName is Frank