Android上的GreenDAO:字节数组作为主键/构建查询包含字节数组属性的Where子句

时间:2013-10-03 11:17:59

标签: android sqlite bytearray where-clause greendao

我目前正在尝试使用包含(字节数组)属性的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' <> '';");

1 个答案:

答案 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_IDINSERT中导致新的自动增量值。 要更新现有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.UUIDORIG.UUID的外键。

ORIG_IDX.REF_ID由触发器填充和更新:

ORIG.REF_ID

ORIG_IDXdb.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创建表UPDATEDELETE,然后使用以下命令查询请求的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!