الروبوت: تصميم SQLite واحد إلى كثير
-
18-09-2019 - |
سؤال
أي شخص لديه تقديم المشورة جيدة حول كيفية تنفيذ تعيين واحد إلى كثير SQLite
استخدام ContentProvider
ب إذا نظرت في Uri ContentProvider#insert(Uri, ContentValues)
يمكنك أن ترى أنه لديه ContentValues
param التي تحتوي على بيانات لإدراجها. المشكلة هي أنه في تنفيذها الحالي ContentValues
لا يدعم put(String, Object)
الطريقة والصفة نهائية لذلك لا أستطيع تمديدها. لماذا هي مشكلة؟ هنا يأتي تصميمي:
لدي 2 طاولات هي في علاقة واحدة إلى كثير. لتمثيل هذه التعليمات البرمجية لدي كائنات نموذجية. يمثل 1st السجل الرئيسي ولديه حقل هو قائمة مثيلات الكائنات الثانية. الآن لدي طريقة مساعد في كائن النموذج رقم 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();
}
}
المحلول
أعتقد أنك تبحث في الطرف الخطأ من العلاقة الواحدة والعديدة.
نلقي نظرة على ContactsContract
مزود المحتوى، على سبيل المثال. يمكن أن تحتوي جهات الاتصال على العديد من عناوين البريد الإلكتروني والعديد من أرقام الهواتف، إلخ. الطريقة التي يتم إنجازها هي القيام بإدراج / تحديثات / حذف "عديدة" الجانب. لإضافة رقم هاتف جديد، تقوم بإدراج رقم هاتف جديد، مما يوفر معرفا للاتصال الذي يتعلق به رقم الهاتف.
يمكنك أن تفعل الشيء نفسه إذا كان لديك قاعدة بيانات SQLite عادي بدون موفر محتوى. يتم تحقيق علاقات واحدة إلى عديدة في قواعد البيانات العلائقية عبر إدراج / تحديثات / حذف على جدول للجانب "العديد من"، كل منها يحتوي على مفتاح أجنبي إلى جانب "واحد".
الآن، من وجهة نظر OO، هذا ليس مثاليا. اهلا وسهلا بكم لإنشاء كائنات المجمع على غرار Orm (فكر في السبات) تتيح لك معالجة مجموعة من الأطفال من الجانب "واحد". يمكن بعد ذلك تشغيل فئة مجموعة ذكية بما فيه الكفاية ومزامنة الجدول "العديد" للمطابقة. ومع ذلك، فإن هذه ليست تافهة بالضرورة لتنفيذها بشكل صحيح.
نصائح أخرى
يمكنك استخدام ContentProviderOperations
لهذا.
إنهم في الأساس العمليات بالجملة مع القدرة على العودة إلى المراجع إلى المعرفات الناتجة عن الصفوف الأصل.
كيف ContentProviderOperations
يمكن استخدامها لتصميم واحد إلى كثير يفسر جيدا في هذه الإجابة: ما هي دلالات withvaluebackReference؟
لذلك سأجيب على سؤالي الخاص. كنت على المسار الصحيح مع وجود جدولين واثنين من الكائنات النموذجية. ما كان مفقودا وما في حيرة مني كان أرغب في إدراج بيانات معقدة مباشرة ContentProvider#insert
في مكالمة واحدة. هذا خطأ. ContentProvider
يجب إنشاء وصيانة هذين الجدولين ولكن القرار الذي يجب أن يملي به جدول يستخدمه المعلمة URI ContentProvider#insert
. وبعد إنه مناسب جدا لاستخدام ContentResolver وأضف طرق مثل "AddFoo" إلى كائن النموذج. هذه الطريقة ستأخذ المعلمة QuestentResolver وفي النهاية هنا هي التسلسل لإدراج سجل معقد:
- إدراج سجل الوالدين من خلال
ContentProvider#insert
والحصول على معرف التسجيل - لكل طفل يوفر المعرف الأصل (Foregn Key) واستخدامه
ContentProvider#insert
مع مختلف URI لإدراج سجلات الأطفال
وبالتالي فإن السؤال الوحيد المتبقي هو كيفية مغلف رمز أعلاه في المعاملة؟