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

Posted

技术标签:

【中文标题】如何在房间数据库dao中附加两个或多个子查询,而这些子查询存储在变量中【英文标题】:How to attach two or more sub queries in room database dao while those subQuery stored in variables 【发布时间】:2021-11-15 07:13:15 【问题描述】:

我正在将我的旧数据库升级到房间数据库,同时从普通 sql 语句转换为房间 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 级别,它会根据各自的标志检查数据库类 我的查询将返回受尊重的数据。

 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;

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

【问题讨论】:

【参考方案1】:

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

演示

这是一个前后 Room 演示,它使用了一个简单的表 TableX,其中包含 id (long/INTEGER PRIMARY KEY)、firstname (String/TEXT) 和 lastName (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 类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 类 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);

请注意,假设是房间,所以没有光标,而是对象数组。

@Database 类 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));
    

首先填充房间前数据库,并使用各种动态生成的排序提取数据,然后将光标转储到日志中。

然后房间数据库基本上模仿上述但显然使用房间,数据输出到日志虽然是通过提取的对象(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

【讨论】:

你好,MikeT 这是非常好的答案,我已经应用它并且它正在工作。谢谢。

以上是关于如何在房间数据库dao中附加两个或多个子查询,而这些子查询存储在变量中的主要内容,如果未能解决你的问题,请参考以下文章

没有内存数据库的单元测试 dao 层

Oracle 多个子查询全部或全部返回

如何在房间持久性库中使用外键

如何将两个或多个文件附加到 Android 上的 SEND 操作

Android 房间查询返回 null

如何在每个操作栏选项卡中维护多个Fragment堆栈或多个子片段