2013-10-03 56 views
2

我當前正在嘗試使用包含(字節數組)屬性的where條件的查詢來選擇條目。這個屬性/列包含一個序列化的UUID。不幸的是,我目前無法更改此列的數據類型,因爲數據庫是由一個單獨的模塊創建和同步的,該模塊僅適用於當前的實現。由於greenDao無法正確處理字節數組作爲主鍵,我試圖以某種方式解決此問題。創建我自己的選擇查詢等將作爲 該物業greenDAO生成過程中所定義的解決方案:Android上的GreenDAO:字節數組作爲主鍵/構建包含字節數組屬性Where子句的查詢

Query query = this.mRandomEntityDao.queryBuilder().where(RandomEntityDao.Properties.RandomProperty.eq(randomByteArray)).build(); 


不幸的是我得到以下錯誤:

Entity randomEntity = schema.addEntity("RandomEntity"); 
... 
randomEntity.addByteArrayProperty("RandomProperty"); 


的查詢使用以下行建與此操作:

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;"); 


同步模塊忽略此列,因此不應該有與任何問題。然後,我創建了一個觸發映射系列化UUID在ID列到新_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

你在這一列中存儲了什麼,每行約有多少字節?爲什麼你不能使用另一種數據類型? – AlexS

+0

我已經正確更新了我的問題;) – AustrianDude

回答

3

關於字節[]又名在greendao BLOB:

看着de.greenrobot.dao.query.WhereCondition.PropertyCondition.checkValueForType條件01目前不支持,因爲如果值的類型爲byte[],以下幾行將始終引發異常。

if (value != null && value.getClass().isArray()) { 
    throw new DaoException("Illegal value: found array, but simple object required"); 
} 

解決方案1 ​​ - 修改並有助於greendao:

您可以修改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停止與此編輯工作或將打破查詢。例如,參數與查詢的綁定可能不適用於數組。

Solutinon 2 - 使用queryRaw(String where, String... selectionArg)

這是非常簡單的,不應該與有關SQLite的一些認識問題。

解決方案3 - 使用查找表

假設原始表:

ORIG 
------------------------------- 
UUID  BLOB 
... 

可以修改ORIG並添加一個自動增量-的PrimaryKey:

db.execSQL("ALTER TABLE 'ORIG' " + 
     "ADD COLUMN 'REF_ID' INT PRIMARYKEY AUTOINCREMENT;"); 

同步服務應該已經關注ORIG.UUID的獨特性並忽略新的ORIG.REF_ID -column。爲了插入新的UUID,同步服務可能會使用INSERTORIG.REF_ID中導致新的自動增量值。 對於更新現有的UUID,同步服務可能會使用UPDATE ... WHERE UUID=?,並且不會創建任何新的ORIG.REF_ID值,但舊值將保留。

總結了ORIG -table在列REF_ID和列UUID之間有一個新的雙射。

現在,您可以創建另一個表:

ORIG_IDX 
------------------------------ 
UUID  TEXT PRIMARYKEY 
REF_ID INT UNIQUE 

(如果你的數據是小於8個字節,也將適用於一個INT代替TEXT,但我不知道是否有一個內置的從BLOBINT。)

ORIG.IDX.UUID將是字符串表示ORIG.UUIDORIG_IDX.REF_IDORIG.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;"); 

創建相應的觸發器,UPDATEDELETE

可以使用greendao創建表ORIGORIG_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)將不可用。

CONCERING AN擴展表:

你可以使用一個string的PrimaryKey列,並提供在實體的保部分轉換的方法。在插入之前,您將必須計算主鍵列。

如果還有其他工具插入數據(例如您的同步服務),您必須在插入前使用觸發器計算您的主鍵。這似乎不可能使用SQLite。因此,主鍵約束將在同步服務插入時失敗,因此此解決方案不適用於主鍵!

+0

我會提供原始查詢,因爲我在greenDAO代碼中更改某些內容猶豫不決(但作爲最後一招,我也會嘗試此選項)。 – AustrianDude

+0

我找到你的答案有關參考表非常有趣,我會試試看。我只想注意一點:'_GREENID'列不會由greenDAO自動增加。對於ID不是由同步模塊自動增加的「ID」列也是如此。它們的唯一性應通過使用UUID作爲它們的值來確保(而條目的兩列之間應存在1:1映射)。但是 - 我可以看到在更新觸發器之前通過同步服務添加行並訪問條目的問題。 – AustrianDude

+0

您可以使UUID列唯一併添加主鍵自動增量列。根據同步服務的邏輯,這不應該導致問題(因爲如果UUID已經存在,同步服務應該關心唯一性並更新行)。然後你可以使用我的文章的toOneMapping。如果您的同步服務不關心更新,但插入主鍵自動增量的所有內容,則必須關心TRIGGER中的UUID唯一性。 – AlexS