Android上的GreenDAO:Byte Array作为主键/构建包含Byte Array属性上Where子句的查询
我目前正在尝试使用一个查询来选择条目,该查询包含(字节数组)属性上的where条件。此属性/列包含序列化的UUID。不幸的是,我目前无法更改此列的数据类型,因为数据库是由一个单独的模块创建和同步的,该模块只能在当前实现中正常工作。由于greenDao无法正确地将字节数组作为主键处理,因此我正在设法解决这个问题。创建我自己的选择查询等将是一个解决方案 该属性在生成greenDAO期间定义为:Android上的GreenDAO:Byte Array作为主键/构建包含Byte Array属性上Where子句的查询,android,sqlite,bytearray,where-clause,greendao,Android,Sqlite,Bytearray,Where Clause,Greendao,我目前正在尝试使用一个查询来选择条目,该查询包含(字节数组)属性上的where条件。此属性/列包含序列化的UUID。不幸的是,我目前无法更改此列的数据类型,因为数据库是由一个单独的模块创建和同步的,该模块只能在当前实现中正常工作。由于greenDao无法正确地将字节数组作为主键处理,因此我正在设法解决这个问题。创建我自己的选择查询等将是一个解决方案 该属性在生成greenDAO期间定义为: Entity randomEntity = schema.addEntity("RandomEntity"
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映射到新的\u 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' <> '';");
db.execSQL(“更新'RANDOMTABLE'集'\u GREENID'=HEX(ID),其中'\u GREENID'';”;
关于greendao中的byte[]又名BLOB:
查看de.greenrobot.dao.query.WhereCondition.PropertyCondition.checkValueForType
目前不支持byte[]
的条件,因为如果值的类型为byte[]
,则以下行将始终引发异常
if (value != null && value.getClass().isArray()) {
throw new DaoException("Illegal value: found array, but simple object required");
}
解决方案1-修改并贡献给绿道:
您可以修改uper行,以便仅当值的类型和属性的类型不匹配时才会引发异常
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");
}
}
也许这已经解决了问题,但greendao中可能还有其他部分停止处理此编辑,或者会中断查询。例如,参数与查询的绑定可能不适用于数组
解决方案2-使用queryRaw(字符串where,字符串…selectionArg)
这是非常直接的,对于SQLite的一些知识来说应该不是问题
解决方案3-使用查找表
假设原始表格:
ORIG
-------------------------------
UUID BLOB
...
您可以修改源代码并添加自动增量主键:
db.execSQL("ALTER TABLE 'ORIG' " +
"ADD COLUMN 'REF_ID' INT PRIMARYKEY AUTOINCREMENT;");
同步服务应该已经考虑到原始UUID的唯一性,并且忽略新的原始参考ID列。对于插入新的UUID,同步服务可能会使用INSERT
在ORIG.REF\u ID
中产生一个新的自动递增值。
要更新现有的UUID
,同步服务可能会使用UPDATE。。。其中UUID=?
且不会创建新的原始参考ID
-值,但会保留旧值
总结了ORIG
-表在列REF\u ID
和列UUID
之间有一个新的双射
现在可以创建另一个表:
ORIG_IDX
------------------------------
UUID TEXT PRIMARYKEY
REF_ID INT UNIQUE
(如果您的数据小于8字节,它也将放入INT
而不是TEXT
,但我不知道是否有从BLOB
到INT
的内置强制转换/转换)
ORIG.IDX.UUID
将是ORIG.UUID
的字符串表示形式。
ORIG.REF\u ID
是ORIG.REF\u 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;");
为UPDATE
和DELETE
创建相应的触发器
您可以使用greendao创建表ORIG
和ORIG_IDX
,然后使用以下内容查询请求的uuid:
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还不受支持,所以dao.load(uuid)
将不可用
关于扩展表:
您可以使用string
primarykey列,并在实体的keep部分提供转换方法。在执行插入之前,必须计算primarykey列
如果有其他工具插入数据(例如同步服务),则必须在插入之前使用触发器计算主键。这似乎不可能使用SQLite。因此,同步服务插入时primarykey约束将失败,因此此解决方案将无法使用primarykey 此列中存储了什么?每行条目大约存储多少字节?为什么不能使用其他数据类型?我已正确更新了我的问题;)我将尝试原始查询,因为我不太愿意更改greenDAO代码中的某些内容(但作为最后手段,我也将尝试此选项)。我发现您关于参考表的答案非常有趣,我将尝试一下。我只想注意一件事:“_GREENID”列并不是由greenDAO自动递增的。对于“ID”列也是如此,该列不会由同步模块自动递增。应该使用UUID作为它们的值来确保它们的唯一性(而条目的两列之间应该存在1:1的映射)。但是-我可以看到通过同步服务添加行以及在更新触发器之前访问条目的问题。您可以使UUID列唯一并添加primarykey自动增量列。根据同步服务的逻辑,这不应该导致问题(因为如果UUID已经存在,同步服务应该关心唯一性并更新行)。然后你就可以用图恩了