我目前正在尝试使用包含(字节数组)属性的where条件的查询来选择条目。此属性/列包含序列化的UUID。不幸的是,我目前无法更改此列的数据类型,因为数据库是由一个单独的模块创建和同步的,该模块只能与当前实现一起正常工作。由于greenDao无法正确处理字节数组作为主键,我试图以某种方式解决这个问题。创建我自己的选择查询等将是一个解决方案 该属性在greenDAO生成期间定义为:
Entity randomEntity = schema.addEntity("RandomEntity");
...
randomEntity.addByteArrayProperty("RandomProperty");
使用以下行构建查询:
Query query = this.mRandomEntityDao.queryBuilder().where(RandomEntityDao.Properties.RandomProperty.eq(randomByteArray)).build();
不幸的是,我在此操作中遇到以下错误:
de.greenrobot.dao.DaoException: Illegal value: found array, but simple object required
at de.greenrobot.dao.query.WhereCondition$PropertyCondition.checkValueForType(WhereCondition.java:75)
...
greenDAO根本不支持这种情况,或者我错过了一些关键的东西吗?不幸的是我不能使用另一种数据类型来处理这个特定的属性。
修改
我目前的解决方法如下:
由于greenDao可以处理作为字符串的主键(直到某一点),并且UUID也可以由此数据类型表示,因此我更改了现有表并添加了以下列:
db.execSQL("ALTER TABLE 'RANDOMTABLE' ADD COLUMN '_GREENID' TEXT;");
同步模块忽略此列,因此不应出现任何问题。然后我创建了一个触发器,将ID
列中的序列化UUID映射到新的_GREENID
列:
db.execSQL("CREATE TRIGGER randomtableGreen AFTER INSERT ON 'RANDOMTABLE' BEGIN " +
"UPDATE 'RANDOMTABLE' SET '_GREENID' = HEX(NEW.ID) WHERE 'RANDOMTABLE'.ID = NEW.ID; " +
"END;");
最后我在表格上运行更新,以防它们在创建触发器之前已经包含一些条目:
db.execSQL("UPDATE 'RANDOMTABLE' SET '_GREENID' = HEX(ID) WHERE '_GREENID' <> '';");
答案 0 :(得分:3)
关于byte [] aka greendao中的BLOB:
目前不支持查看de.greenrobot.dao.query.WhereCondition.PropertyCondition.checkValueForType
的{{1}}条件,因为如果值类型为byte[]
,则以下行将始终抛出异常。
byte[]
解决方案1 - 修改并为greendao做出贡献:
您可以修改超线,以便仅在值的类型和属性的类型不适合时抛出异常。
if (value != null && value.getClass().isArray()) {
throw new DaoException("Illegal value: found array, but simple object required");
}
也许这已经解决了问题,但是greendao中可能还有其他部分停止使用此编辑或者会破坏查询。例如,参数与查询的绑定可能不适用于数组。
Solutinon 2 - 使用if (value != null) {
if (value.getClass().isArray() && !property.type.isArray()) {
throw new DaoException("Illegal value: found array, but " +
"simple object required");
}
if (!value.getClass().isArray() && property.type.isArray()) {
throw new DaoException("Illegal value: found simple object, " +
"but array required");
}
}
这非常简单,不应该对SQLite有一些了解。
解决方案3 - 使用查找表
假设原始表:
queryRaw(String where, String... selectionArg)
您可以修改ORIG
-------------------------------
UUID BLOB
...
并添加autoincrement-primarykey:
ORIG
同步服务应该已经关注db.execSQL("ALTER TABLE 'ORIG' " +
"ADD COLUMN 'REF_ID' INT PRIMARYKEY AUTOINCREMENT;");
的唯一性,并忽略新的ORIG.UUID
- 列。为了插入新的UUID,同步服务可能会使用ORIG.REF_ID
在INSERT
中导致新的自动增量值。
要更新现有ORIG.REF_ID
,同步服务可能会使用UUID
,并且不会创建新的UPDATE ... WHERE UUID=?
- 值,但会保留旧值。
汇总ORIG.REF_ID
- 表在列ORIG
和列REF_ID
之间有一个新的Bijection。
现在您可以创建另一个表:
UUID
(如果您的数据小于8个字节,它也适合ORIG_IDX
------------------------------
UUID TEXT PRIMARYKEY
REF_ID INT UNIQUE
而不是INT
,但我不知道是否存在来自{{1的内置强制转换/转换转到TEXT
。)
BLOB
将是INT
的字符串表示形式。
ORIG.IDX.UUID
是ORIG.UUID
的外键。
ORIG_IDX.REF_ID
由触发器填充和更新:
ORIG.REF_ID
为ORIG_IDX
和db.execSQL("CREATE TRIGGER T_ORIG_AI AFTER INSERT ON 'ORIG' BEGIN " +
"INSERT 'ORIG_IDX' SET 'REF_ID' = NEW.REF_ID, 'UUID' = NEW.UUID" +
"END;");
创建相应的触发器。
您可以使用greendao创建表UPDATE
和DELETE
,然后使用以下命令查询请求的uuid:
ORIG
我认为还不支持String-primarykey,因此ORIG_IDX
将无法使用。
关注扩展表:
您可以使用public Orig getOrig(String uuid) {
OrigIdx origIdx = OrigIdxDao.queryBuilder().where(
QrigIdxDao.Properties.UUID.eq(uuid)).unique();
if (origIdx != null) {
return origIdx.getOrig();
}
return null;
}
primarykey-column并在实体的保留部分中提供转换方法。在插入之前,您必须计算primarykey-column。
如果有其他工具插入数据(例如您的同步服务),您必须在插入发生之前使用触发器来计算主键。使用SQLite似乎不太可能。因此,同步服务在插入时,primarykey-constraint将失败,因此该解决方案不适用于primarykey!