سؤال

الهدف:تحديث قاعدة البيانات من بيانات XML

العملية:

  • تبدأ الصفقة
  • حذف كافة الصفوف الموجودة من الجداول
  • لكل العنصر الرئيسي من تحليل XML إدراج صف في الجدول الرئيسي والحصول على PK
  • في كل طفل من العنصر الرئيسي إدراج سجل في الجدول 2 توفير FK من الخطوة السابقة
  • ارتكاب الصفقة

جميلة القياسية الاشياء بقدر db العمليات.المشكلة هي أن عمليات الخام لا تتم داخل ContentProvider ولكن بدلا من ذلك باستخدام ContentResolver حتى أدخل على سبيل المثال يبدو resolver.insert(CONTENT_URI, contentValues).على ContentResolver API لا يبدو أن يكون أي شيء يخص المعاملات وأنا لا يمكن استخدام bulkInsert أنا منذ أن تدرج في الجداول 2 بشكل متقطع (زائد أريد أن يكون delete داخل الصفقة كذلك).

كنت أفكر في تسجيل بلدي حسب الطلب ContentProvider كما المستمع باستخدام registerContentObserver ولكن منذ ContentResolver#acquireProvider طرق مخفية كيف يمكنني الحصول على حق مرجع ؟

أنا من الحظ ؟

هل كانت مفيدة؟

المحلول

لقد رأيت ذلك في التعليمات البرمجية المصدر لتطبيق Google I / O، تجاوزها ContentProviderapplyBatch() طريقة واستخدام المعاملات داخلها. لذلك، يمكنك إنشاء دفعة من ContentProviderOperation S ثم اتصل getContentResolver().applyBatch(uri_authority, batch).

أخطط لاستخدام هذا النهج لمعرفة كيف يعمل. أنا فضولي إذا حاول أي شخص آخر ذلك.

نصائح أخرى

فمن الممكن أن تفعل الصفقة على أساس متعدد الجدول إدراج بدلا نظيفة منذ الروبوت 2.1 باستخدام ContentProviderOperation ، كما ذكر kaciula.

عند بناء ContentProviderOperation كائن يمكنك الاتصال .withValueBackReference(fieldName, refNr).عند تشغيل تطبيق باستخدام applyBatch ، والنتيجة هي أن ContentValues الكائن الذي تم توفيره مع إدراج() الدعوة سوف يكون عدد صحيح حقن.صحيح سوف يكون مرتبطا مع fieldName سلسلة وقيمته يتم استردادها من ContentProviderResult سابقا تطبيق ContentProviderOperation ، فهرستها من قبل refNr.

يرجى الرجوع إلى نموذج التعليمات البرمجية أدناه.في العينة ، على التوالي يتم إدراجها في جدول1 ، مما أدى معرف (في هذه الحالة "1") هو قيمة عند إدراج صف في الجدول 2.الإيجاز ، ContentProvider غير متصل بقاعدة بيانات.في ContentProvider ، وهناك المطبوعات حيث سيكون مناسبة لإضافة الصفقة التعامل.

public class BatchTestActivity extends Activity {
    /** Called when the activity is first created. */
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        ArrayList<ContentProviderOperation> list = new
            ArrayList<ContentProviderOperation>();

        list.add(ContentProviderOperation.
            newInsert(BatchContentProvider.FIRST_URI).build());
        ContentValues cv = new ContentValues();
        cv.put("name", "second_name");
        cv.put("refId", 23);

        // In this example, "refId" in the contentValues will be overwritten by
        // the result from the first insert operation, indexed by 0
        list.add(ContentProviderOperation.
            newInsert(BatchContentProvider.SECOND_URI).
            withValues(cv).withValueBackReference("refId", 0).build());

        try {
            getContentResolver().applyBatch(
                BatchContentProvider.AUTHORITY, list);
        } catch (RemoteException e) {
            e.printStackTrace();
        } catch (OperationApplicationException e) {
            e.printStackTrace();
        }
    }
}

public class BatchContentProvider extends ContentProvider {

    private static final String SCHEME = "content://";
    public static final String AUTHORITY = "com.test.batch";

    public static final Uri FIRST_URI =
        Uri.parse(SCHEME + AUTHORITY + "/" + "table1");
    public static final Uri SECOND_URI =
        Uri.parse(SCHEME + AUTHORITY + "/" + "table2");


    public ContentProviderResult[] applyBatch(
        ArrayList<ContentProviderOperation> operations)
            throws OperationApplicationException {
        System.out.println("starting transaction");
        ContentProviderResult[] result;
        try {
            result = super.applyBatch(operations);
        } catch (OperationApplicationException e) {
            System.out.println("aborting transaction");
            throw e;
        }
        System.out.println("ending transaction");
        return result;
    }

    public Uri insert(Uri uri, ContentValues values) {
        // this printout will have a proper value when
        // the second operation is applied
        System.out.println("" + values);

        return ContentUris.withAppendedId(uri, 1);
    }

    // other overrides omitted for brevity
}

حسنا - لذلك هذا لا dengle بلا هدف: الطريقة الوحيدة التي يمكنني التفكير فيها هي إبرام إيقاف التشغيل وإنشاءات الإنتاجية كطلبات استعلام قائمة على المواقع URL. شيء مثل ContentResolver.query(START_TRANSACTION, null, null, null, null). وبعد ثم في ContentProvider#query استنادا إلى بدء أو نهاية عنوان URL المسجل

يمكنك الحصول على تطبيق كائن موفر المحتوى نفسه (إذا كان في نفس العملية، تلميح: يمكنك التحكم في عملية المزود باستخدام MultipRocess = "True" أو العملية = "" http://developer.android.com/guide/topics/manifest/provider-element.html.) استخدام contentproviderclient.getlocalcontentprovider () والتي يمكن صيدها على تنفيذ المزود الخاص بك والتي يمكن أن توفر وظائف إضافية مثل إعادة تعيين () التي تغلق وحذف قاعدة البيانات ويمكنك أيضا إرجاع مثيل فئة المعاملات المخصصة مع طرق حفظ () وإغلاق () وبعد

public class Transaction {
    protected Transaction (SQLiteDatabase database) {
        this.database = database;
        database.beginTransaction ();
    }

    public void save () {
        this.database.setTransactionSuccessful ();
    }

    public void close () {
        this.database.endTransaction ();
    }

    private SQLiteDatabase database;
}

public Transaction createTransaction () {
    return new Transaction (this.dbHelper.getWritableDatabase ());
}

ثم:

ContentProviderClient client = getContentResolver ().acquireContentProviderClient (Contract.authorityLocal);
Transaction tx = ((LocalContentProvider) client.getLocalContentProvider ()).createTransaction ();
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top