2010-02-05 10 views
10

किसी को भी कैसे एक-से-कई SQLite के लिए मैपिंग लागू करने के लिए ContentProvider के प्रयोग पर अच्छा सलाह है? यदि आप Uri ContentProvider#insert(Uri, ContentValues) देखते हैं तो आप देख सकते हैं कि इसमें ContentValues पैरा है जिसमें सम्मिलित करने के लिए डेटा शामिल है। समस्या यह है कि वर्तमान कार्यान्वयन में ContentValuesput(String, Object) विधि का समर्थन नहीं करता है और कक्षा अंतिम है इसलिए मैं इसे विस्तारित नहीं कर सकता। यह एक समस्या क्यों है? यहाँ मेरी डिजाइन आता है:एंड्रॉयड: SQLite एक-से-कई डिजाइन

2 टेबल जो एक-से-अनेक संबंध में हैं। कोड में इन्हें प्रस्तुत करने के लिए मेरे पास 2 मॉडल ऑब्जेक्ट्स हैं। पहला मुख्य रिकॉर्ड का प्रतिनिधित्व करता है और इसमें एक ऐसा क्षेत्र है जो दूसरे ऑब्जेक्ट उदाहरणों की एक सूची है। अब मेरे पास मॉडल ऑब्जेक्ट # 1 में एक सहायक विधि है जो वर्तमान ऑब्जेक्ट से उत्पन्न ContentValues लौटाती है। ContentValues#put ओवरलोडेड विधियों के साथ एक आदिम फ़ील्ड को पॉप्युलेट करना मुश्किल है लेकिन मैं सूची के लिए भाग्य से बाहर हूं। तो वर्तमान में मेरी दूसरी तालिका पंक्ति केवल एक स्ट्रिंग मान है क्योंकि मैं एक अल्पविराम सीमित स्ट्रिंग उत्पन्न करता हूं जो तब मैं ContentProvider#insert के अंदर स्ट्रिंग [] को दोहराता हूं। यह भाग्यशाली लगता है, तो शायद कोई संकेत दे सकता है कि इसे क्लीनर फैशन में कैसे किया जा सकता है।

यहाँ कुछ कोड है। मॉडल कक्षा से पहले:

public ContentValues toContentValues() { 
    ContentValues values = new ContentValues(); 
    values.put(ITEM_ID, itemId); 
    values.put(NAME, name); 
    values.put(TYPES, concat(types)); 
    return values; 
} 

private String concat(String[] values) { /* trivial */} 

और यहाँ ContentProvider#insert विधि

public Uri insert(Uri uri, ContentValues values) { 
    SQLiteDatabase db = dbHelper.getWritableDatabase(); 
    db.beginTransaction(); 
    try { 
     // populate types 
     String[] types = ((String)values.get(Offer.TYPES)).split("|"); 
     // we no longer need it 
     values.remove(Offer.TYPES); 
     // first insert row into OFFERS 
     final long rowId = db.insert("offers", Offer.NAME, values); 
     if (rowId > 0 && types != null) { 
      // now insert all types for the row 
      for (String t : types) { 
       ContentValues type = new ContentValues(8); 
       type.put(Offer.OFFER_ID, rowId); 
       type.put(Offer.TYPE, t); 
       // insert values into second table 
       db.insert("types", Offer.TYPE, type); 
      } 
     } 
     db.setTransactionSuccessful(); 
     return ContentUris.withAppendedId(Offer.CONTENT_URI, rowId); 
    } catch (Exception e) { 
     Log.e(TAG, "Failed to insert record", e); 
    } finally { 
     db.endTransaction(); 
    } 

} 
+0

हाँ, मैं एक ही समस्या है ... एक लेन-देन में अनेक निवेशन ने लिफाफे में कैसे? मैंने दो विशेष यूआरआई जोड़कर इसे प्रबंधित किया: एक संक्रमण की शुरुआत के लिए और अंत में एक। मुझे पता है कि यह सबसे अच्छा समाधान नहीं है। यदि आपके पास बेहतर है तो मैं इसकी सराहना करूंगा! – Bhiefer

उत्तर

5

मुझे लगता है कि आप एक-से-अनेक संबंध के गलत छोर पर देख रहे हैं के संस्करण नीचे slimmed है।

उदाहरण के लिए, ContactsContract सामग्री प्रदाता पर एक नजर डालें। संपर्कों में कई ईमेल पते, कई फोन नंबर इत्यादि हो सकते हैं। जिस तरह से पूरा किया जाता है वह "कई" पक्ष पर आवेषण/अपडेट/हटाना कर रहा है। एक नया फोन नंबर जोड़ने के लिए, आप एक नया फोन नंबर डालते हैं, जो संपर्क की एक आईडी प्रदान करता है जिसके लिए फोन नंबर संबंधित है।

यदि आप कोई सामग्री प्रदाता के साथ एक सादे SQLite डेटाबेस था भी ऐसा ही होगा। रिलेशनल डेटाबेस में एक से कई रिश्तों को "कई" पक्ष के लिए एक टेबल पर आवेषण/अद्यतन/हटाए जाने के माध्यम से हासिल किया जाता है, प्रत्येक में "एक" पक्ष में एक विदेशी कुंजी होती है।

अब, एक OO दृष्टिकोण से, यह नहीं आदर्श है। ओआरएम-स्टाइल रैपर ऑब्जेक्ट्स (हाइबरनेट सोचें) बनाने के लिए आपका स्वागत है जो आपको "एक" पक्ष से बच्चों के संग्रह में हेरफेर करने की अनुमति देता है। एक पर्याप्त बुद्धिमान संग्रह वर्ग फिर से बदल सकता है और "कई" तालिका मिलान करने के लिए सिंक्रनाइज़ कर सकता है। हालांकि, यह ठीक से लागू करने के लिए जरूरी नहीं है।

+0

वैसे मेरे पास एक मुख्य रिकॉर्ड है, जो व्यक्ति मैन फोन फोनर्स का संदर्भ देता है। इसलिए मैं व्यक्ति रिकॉर्ड डालता हूं और इसकी कुंजी प्राप्त करता हूं, फिर मैं फोन टेबल में रिकॉर्ड का एक बड़ा हिस्सा डालता हूं जिसमें प्रत्येक व्यक्ति को विदेशी कुंजी के साथ आपूर्ति की जाती है। सुंदर मानक सामान। तब मुझे जावा पक्ष पर इस संबंध का प्रतिनिधित्व करने में कोई समस्या नहीं है, जिसमें मेरी दो ऑब्जेक्ट ऑब्जेक्ट्स और व्यक्ति ऑब्जेक्ट में फ़ोन का संग्रह है। जहां मुझे मुश्किल समय है प्रदाता एपीआई में प्लग करना है। मैं संपर्कों का अध्ययन करने जा रहा हूं, संकेत के लिए धन्यवाद और – Bostone

+0

पर रिपोर्ट करें वास्तव में मेरे आवेषण गतिशील नहीं हैं, मूल रूप से मैं एक्सएमएल का विश्लेषण करता हूं और रिकॉर्ड डालता हूं। एक बार वहां मैं केवल बिना किसी हेरफेर के इन्हें पढ़ूंगा। मुझे लगता है कि मैं प्रति सामग्री एक सामग्री रिसेल्वर का उपयोग कर सकता हूं लेकिन मैं इस कार्यक्षमता को ContentProvider के रूप में भी बेनकाब करना चाहता हूं और फिर मुझे फिर से कठिन समय हो रहा है – Bostone

+0

असल में मैं 1.5 में संपर्क कक्षा के माध्यम से जा रहा हूं - मुझे लगता है कि टिप के लिए धन्यवाद मुझे वास्तव में क्या चाहिए – Bostone

4

तो मैं अपने स्वयं के प्रश्न का उत्तर देने जा रहा हूं। मैं दो टेबल और दो मॉडल ऑब्जेक्ट्स के साथ सही रास्ते पर था। क्या लापता था और मुझे क्या उलझन में था कि मैं सीधे एक ही कॉल में ContentProvider#insert के माध्यम से जटिल डेटा डालना चाहता था। ये गलत है। ContentProvider इन दो तालिकाओं को बनाए और बनाए रखना चाहिए लेकिन उपयोग करने के लिए तालिका पर निर्णय ContentProvider#insert के उरी पैरामीटर द्वारा निर्धारित किया जाना चाहिए। ContentResolver का उपयोग करना और मॉडल ऑब्जेक्ट में "addFoo" जैसी विधियां जोड़ें।इस तरह के विधि ContentResolver पैरामीटर ले जाएगा और अंत में यहाँ एक जटिल रिकॉर्ड सम्मिलित करने अनुक्रम हैं: ContentProvider#insert के माध्यम से

  1. सम्मिलित माता पिता रिकॉर्ड और रिकॉर्ड आईडी
  2. प्राप्त प्रत्येक बच्चे प्रति अभिभावक आईडी (foregn कुंजी) और उपयोग प्रदान ContentProvider#insert अलग उरी के साथ बच्चे रिकॉर्ड

डालने के लिए तो केवल शेष सवाल यह है कि लेनदेन में उपरोक्त कोड लिफाफे में है?

5

आप इसके लिए ContentProviderOperations का उपयोग कर सकते हैं।

वे मूल रूप से थोक संचालन हैं जो अभिभावक पंक्तियों के लिए उत्पन्न पहचानकर्ताओं के बैक-रेफरेंस की क्षमता के साथ हैं।

कैसे ContentProviderOperations एक एक-से-कई डिजाइन के लिए इस्तेमाल किया जा सकता बहुत अच्छी तरह से इस उत्तर से समझाया गया है: What are the semantics of withValueBackReference?

संबंधित मुद्दे