有没有办法用Android Room创建可重用的通用基类DAO?
public interface BaseDao<T> {
@Insert
void insert(T object);
@Update
void update(T object);
@Query("SELECT * FROM #{T} WHERE id = :id")
void findAll(int id);
@Delete
void delete(T object);
}
public interface FooDao extends BaseDao<FooObject> { ... }
public interface BarDao extends BaseDao<BarEntity> { ... }
我无法找到实现这一目标的任何方法,而无需声明相同的接口成员并为每个子类编写查询。在处理大量类似的DAO时,这变得非常乏味......
答案 0 :(得分:9)
今天,2017年8月8日,版本 1.0.0-alpha8 下面的Dao工作。我可以让其他Dao英雄级别的GenericDao。
@Dao
public interface GenericDao<T> {
@Insert(onConflict = OnConflictStrategy.REPLACE)
void insert(T... entity);
@Update
void update(T entity);
@Delete
void delete(T entity);
}
但是,GenericDao不能包含在我的数据库类
中答案 1 :(得分:2)
我有findAll的解决方案。
该BaseDao中的代码:
...
public List<T> findAll() {
SimpleSQLiteQuery query = new SimpleSQLiteQuery(
"select * from " + getTableName()
);
return doFindAll(query);
}
...
public String getTableName() {
// Below is based on your inheritance chain
Class clazz = (Class)
((ParameterizedType) getClass().getSuperclass().getGenericSuperclass())
.getActualTypeArguments()[0];
// tableName = StringUtil.toSnakeCase(clazz.getSimpleName());
String tableName = clazz.getSimpleName();
return tableName;
}
...
@RawQuery
protected abstract List<T> doFindAll(SupportSQLiteQuery query);
和其他刀像:
@Dao
public abstract class UserDao extends AppDao<User> {
}
仅此而已
这个想法是
如果您希望使用接口而不是抽象类,则可以尝试使用Java 8的可选方法。
如您所见,它并不漂亮,但可以工作。
答案 2 :(得分:1)
AFAIK,您只能对insert()
,update()
和delete()
执行此操作,因为它不需要在编译时需要验证的特定SQL语句。
示例:
BaseDao.java
public interface BaseDao<T> {
@Insert
void insert(T obj);
@Insert
void insert(T... obj);
@Update
void update(T obj);
@Delete
void delete(T obj);
}
UserDao.java
@Dao
abstract class UserDao implements BaseDao<User> {
@Query("SELECT * FROM User")
abstract List<User> getUser();
}
答案 3 :(得分:0)
泛型findAll函数:
基本存储库和dao:
abstract class BaseRepository<T>(private val entityClass: Class<T>) {
abstract val dao: BaseDao<T>
fun findAll(): List<T> {
return dao.findAll(SimpleSQLiteQuery("SELECT * FROM ${DatabaseService.getTableName(entityClass)}"))
}
}
interface BaseDao<T> {
@RawQuery
fun findAll(query: SupportSQLiteQuery): List<T>
}
数据库服务:
object DatabaseService {
fun getEntityClass(tableName: String): Class<*>? {
return when (tableName) {
"SomeTableThatDoesntMatchClassName" -> MyClass::class.java
else -> Class.forName(tableName)
}
}
fun getTableName(entityClass: Class<*>): String? {
return when (entityClass) {
MyClass::class.java -> "SomeTableThatDoesntMatchClassName"
else -> entityClass.simpleName
}
}
}
示例回购和dao:
class UserRepository : BaseRepository<User>(User::class.java) {
override val dao: UserDao
get() = database.userDao
}
@Dao
interface UserDao : BaseDao<User>
答案 4 :(得分:0)
应按以下方式实现:
interface BaseDao<T : BaseEntity> {
@Insert
fun insert(entity: T)
@Insert
fun insert(vararg entities: T)
@Update
fun update(entity: T)
@Delete
fun delete(entity: T)
fun getAll(): LiveData<List<T>>
}
@Dao
abstract class MotorDao : BaseDao<Motor> {
@Query("select * from Motor")
abstract override fun getAll(): LiveData<List<Motor>>
}
答案 5 :(得分:-1)
虽然我同意你的想法,但答案是肯定的。有几个原因。
当fooDao_Impl.java
课程生成@Dao fooDao extends BaseDao<Foo>
时,您会遇到很多&#34;找不到符号T&#34;错误。这是由于Room用于生成dao实现的方法。这种方法不能支持您期望的结果,并且不太可能很快改变(在我看来,由于类型擦除)。
即使已解决此问题,Room也不支持动态@Dao
查询,以防止SQL注入。这意味着您只能将值动态插入查询,而不是列名,表名或查询命令。在示例中,您无法使用#{T}
,因为它会违反此原则。理论上,如果解决了第1点中详述的问题,您可以通过用户插入,删除和更新。