4

我正在實施PRIVATE ContentProvider,該表格包含很少關係的表格(一對多,多對多)。在我目前的實現中,所有的表都可以通過URI訪問。 我該如何簡化接口,以便不必通過URI來訪問內部'through'表?使用ContentProvider插入到多個表格

例如,我有一個POSTS表,每個POST都有很多TAGS通過TAGGINGS表。 我想僅與POSTS URI進行交互,並在ContentProvider內部執行「私人」工作。

對於query它簡單地返回與連接表的遊標,但我該怎麼做與insert?是bulkInsert我應該看看?

回答

1

只要提供所需的值,您就可以自由插入乘法表。

例如:

ContentValues v = new ContentValues(); 
v.put("title","post1"); 
v.put("tag","tag1"); 
getProvider().insert(POST_URI,v); 

insert實現,您可以檢查是否字段(tag)屬於其它表exists.If這樣做,意味着你應該做一些額外的工作 - 第一次插入標籤如果它不存在,請在標籤和剛剛插入的帖子之間建立正確的關聯。

您可以查看android聯繫人的源代碼以供參考。

UPDATE:

要插入乘標籤,一個黑客-Y的辦法是插入一個逗號分隔的字符串。這不是優雅,但它的作品。

+0

一個帖子有很多標籤,所以我需要傳遞一個數組或一組標籤。我沒有看到它可能與ContentValues。 – 2012-07-15 13:48:25

+0

@Gal:要插入多個標記,一種hack-y方法是插入逗號分隔的字符串。這不是優雅,但它的作品。 – pierrotlefou 2012-07-17 01:15:13

7

這是ContentProvider的侷限性。如果您沒有將數據公開給其他應用程序,則可以使用自定義數據庫適配器實現,並使用方法和查詢直接觸及您的需求。

bulkInsert()在這種情況下不起作用,因爲它只將行一次插入到一個表中。但請看ContentProvider.applyBatch()方法和ContentProviderOperation,ContentProviderOperation.Builder類(您可能需要withValueBackReference()進行一對多插入)。

這些鏈接可以幫助你瞭解如何使用它們:

http://www.grokkingandroid.com/better-performance-with-contentprovideroperation/ http://www.grokkingandroid.com/androids-contentprovideroperation-withbackreference-explained/ What are the semantics of withValueBackReference?

但注意,使用ContentProviderOperationbulkInsert()慢得多,如果你是在一次插入多行,因爲它解析Uri(字符串比較)每次操作將要執行時。這樣做你仍然必須公開Uri插入到子表中。

如果你決定使用applyBatch(),將其覆蓋在你的供應商,因此在一個事務中執行所有操作,讓你保留數據的一致性,加快數據庫操作:

@Override 
public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations) 
     throws OperationApplicationException { 
    final SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 
    db.beginTransaction(); 
    try { 
     ContentProviderResult[] results = super.applyBatch(operations); 
     db.setTransactionSuccessful(); 
     return results; 
    } finally { 
     db.endTransaction(); 
    } 
} 
+0

所以不暴露子表的唯一方法是使用'applyBatch'? – 2012-07-15 14:05:17

+0

你仍然需要定義uri來插入子表,這就是ContentProvider被處理的方式(如果你想禁止查詢子表,你可以在子表上使用IllegalArgumentException對子查詢進行操作),對內容提供者的訪問是基於Uris並且提供者主要用於一個表,但在涉及表之間的關係時它們有侷限性,但公開單獨的uri以插入子表沒有什麼錯誤,發佈的applyBatch()方法可幫助您準備操作並在一個表中執行它們事務 – biegleux 2012-07-15 14:18:11

+0

這是一個使用內容提供者而不是自己的數據庫適配器實現的折衷 – biegleux 2012-07-15 14:21:51

1

只是爲了得到這個權利:你想擁有一個URI並通過對ContentProvider的一次插入調用來插入一個帖子及其所有標籤?正確?

問題是,您需要具有ContentValues對象中的所有值。數據庫中規範化有一個原因。儘管如此,它可能是可行的。對於標籤,這應該很容易。只需使用一個所有標籤的字符串。例如「android,ios,bada,wp7」並在你的插入方法中解析這個字符串。

你也可以使用命名加整數約定。只要有tag1,tag2,... tagX,你就可以從ContentProvider的插入方法中讀取這些值。

既不優雅,但會工作。

在這種情況下,bulkInsert或applyBatch在您的代碼中沒有位置。只有在一次和一次事務內使用多個對您的ContentProvider的調用時,它們纔會發揮作用。

但我認爲更好的解決方案確實是實際使用biegleux所描述的多種操作。

0

由於您將要插入多個表中,所以普通的SQLiteDatabase.insert輔助函數將不起作用。但是,這是完全可行的,性能優良的方式。

您需要從將要插入ContentProvider的用戶的端點來看待此問題,即使它只是您自己。所以首先爲你們所有的字段定義名字或者鍵。由於您不會使用SQLiteDatabase.insert,因此實際上並不需要將它們命名爲與數據庫字段相同。沒有一個名稱應該重複。例如,如果您有兩個不同表中的字段重疊,則TableA中的tagTableB可能與TableA.tagTableB.tag中的那些字段的名稱重疊。或者使用語義命名來獲得更多不會相互衝突的描述性名稱。

接下來,您需要使用SQLiteStatement來創建插入查詢,每answer。確保您在createInsert中使用的名稱與ContentProvider的調用方用作ContentValues中的鍵的名稱相同。