Android Room通用DAO

8

你好Stack,我正在开发一个使用Android Room 1.0.0 Alpha 5的Android项目。我遇到的主要问题是每次需要从Room中调用DAO时,我都需要像这样做:

Activity.java:

...
AppDatabase db = Room.databaseBuilder(context, AppDatabase.class, "Storage").build();
Table1 table = new Table1();
table.setId(1);
table.setName("Hello");
new AccessDB().execute(1);

/* Generic AccessDB needed */
private class AccessDB extends AsyncTask<Integer,Void,List<Table1>> {

    @Override
    protected List<Table1> doInBackground(Integer... param) {
        switch(param[0]) {
            case 1:
                return db.Table1DAO().create();
            case 2:
                return db.Table1DAO().read();
        }
        return new ArrayList<>();
    }

    @Override
    protected void onPostExecute(List<Table1> list) {
        processData(list);
    }
}
...

我知道我可以从主线程访问Room数据库,并且这会缩小代码,但我认为这不是一个好的实践,因为每次处理数据时都会锁定活动。
所以如果我需要插入或读取“Table2”中的数据,我将不得不再次执行相同的操作,如果我能将实体类型转换为类似于“T”的泛型,然后制作一个通用的“AccessDB”就好了。
但由于我对Java不太熟悉...我目前正在努力解决这个问题。
下面是一些实例的其他代码。
AppDatabase.java:
@Database(entities = {Table1.class, Table2.class, Table3.class}, version = 1)
public abstract class AppDatabase extends RoomDatabase {
    public abstract Table1DAO Table1DAO();
    public abstract Table2DAO Table2DAO();
    public abstract Table3DAO Table3DAO();
}

Table1.java:

@Entity
public class Table1 {
    /* setters & getters */
    @PrimaryKey(autoGenerate = true)
    private int id;
    private String name;
}

Table1DAO.java:

@Dao public interface Table1DAO {
    @Query("SELECT * FROM Table1")
    List<Table1> read(Table1 table);

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    List<Long> create(Table1... table);
}

感谢大家的帮助。涉及IT技术相关内容。
2个回答

8
你可以使用继承并创建一个名为BaseDao的类,然后让所有子Dao都去实现它。这样你就不需要一遍又一遍地重复编写相同的方法了。
interface BaseDao<T> {

/**
 * Insert an object in the database.
 *
 * @param obj the object to be inserted.
 */
@Insert
fun insert(obj: T)

/**
 * Insert an array of objects in the database.
 *
 * @param obj the objects to be inserted.
 */
@Insert
fun insert(vararg obj: T)

/**
 * Update an object from the database.
 *
 * @param obj the object to be updated
 */
@Update
fun update(obj: T)

/**
 * Delete an object from the database
 *
 * @param obj the object to be deleted
 */
@Delete
fun delete(obj: T)
}

请阅读更多相关内容:https://gist.github.com/florina-muntenescu/1c78858f286d196d545c038a71a3e864#file-basedao-kt 原作者为Florina。

1
我想到了非常类似的东西,但我认为这个更好,似乎它也不能有默认查询,但它非常有帮助。 - Basher SG
我只看到 Kotlin 中的 Dao 继承。在 Java 中也可以使用,对吗? - mike_x_
是的,它也适用于Java;因为Java支持继承。 - Akshay Chordiya
我们是否仍然需要为每个可查询实体创建特定的DAO子类型?只使用一个通用DAO似乎是不可能的,至少因为我们必须为查询方法指定表名。为什么我们甚至还要为基本的SELECT编写SQL呢?INSERT、DELETE和UPDATE似乎可以自行完成! - Arthur Khazbs

2

我对Akshay Chordiya的答案进行了一些尝试,但需要两个补充:

  • 能够插入/更新列表
  • 返回值以监视插入/更新成功

这是我想出来的:

import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Update

/**
 * List of all generic DB actions
 * All use suspend to force kotlin coroutine usage, remove if not required
 */
@Dao
interface BaseDao<T> {

    // insert single
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun insert(obj: T?): Long

    // insert List
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun insert(obj: List<T>?) : List<Long>

    // update List
    @Update
    suspend fun update(obj: List<T>?): Int

}

@Dao
interface MyObjectDao : BaseDao<MyObject> {

    @Query("SELECT * from $TABLE_NAME WHERE $COL_ID = :id")
    suspend fun getById(id: Long): MyObject

}

可以这样调用:
val ids = MyObjectDao.insert(objectList)

它是否会根据对象类型来决定Dao? - Sneha Bansal
1
找到了一个有用的示例,展示了如何完成类似的事情:https://medium.com/@berryhuang/android-room-generic-dao-27cfc21a4912 - XZen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接