28 – حفظ المعطيات ضمن قاعدة المعطيات SQL

ملاحظة : الموضوع عبارة عن حلقة من حلقات سلسلة برمجة وتطوير اندرويد Android Development

اندرويد : حفظ المعطيات ضمن قاعدة المعطيات SQL  

السلام عليكم ورحمة الله وبركاته

سوف نتعلم ضمن هذا الدرس الامور التالية :

  • تعريف Schema و Contract
  • تعريف قاعدة معطيات باستخدام SQL Helper
  • وضع المعلومات ضمن قاعدة المعطيات put information into a Database
  • قراءة المعلومات من قاعدة المعطيات Read information from a Database
  • حذف المعلومات من قاعدة المعطيات Delete Information from a Database
  • تحديث قاعدة المعطيات Update a Database

تعتبر عملية تخزين المعطيات ضمن قاعدة المعطيات عملية مناسبة للمعطيات المتكررة والمهيكلة, مثل معلومات الاتصال.

نفترض من هذا الدرس بأن على المام ومعرفة بقواعد المعطيات SQL بشكل عام , ويساعدك على البدء بقواعد المعطيات SQLite على اندرويد.

الواجهات البرمجية API التي سوفت تحتاج لاستخدامها على اندرويد متوافرة ضمن حزمة android.database.sqlite.

تعريف Scheme  و Contract

تعتبر ال schema احد اهم الامور الاساسية ضمن قواعد معطيات SQL: وهي عبارة عن تصريح رسمي عن كيفية تنظيم قاعدة المعطيات.

تظهر وتنعكس السكيما Schema بواسطة عبارة SQL التي سوف تستخدمها لإنشاء قاعدة المعطيات.

قد تجد بأنه من المفيد ان تقوم بإنشاء صف مرافق companion class ويعرف ب Contract class.والذي يقوم بشكل صريح بتحديد تنسيق السكيما بطريقة ممنهجة وبسيطة.

Contract class عبارة عن container للثوابت التي تعرف اسماء خاصة ب URLs, الجداول tables, والاعمدة columns.
يمكنك صف contract من استخدام نفس الثوابت عبر كل الصفوف ضمن نفس الحزمة.هذا يمكنك من تغيير اسم العمود في مكان واحد وسوف ينتقل التغيير عبر كامل الكود.

من احد الطرق الجيدة لتنظيم صف contract تكمن في وضع التعاريف العامة على مستوى قاعدة المعطيات كلها ضمن مستوى الجذر من الصفroot level of the class. ومن ثم تنشأ الصف الداخلي لكل جدول مع اعمدته.

ملاحظة : عبر تحقيق الواجهةinterface  BaseColumns, فإنه يصبح بامكان صفوفك الداخلية ان ترث الحقل المفتاحي primary key field والذي يدعى _ID والذي تتوقع بعض صفوف اندرويد الداخلية (مثل cursor adaptors ) امتلاكه. هذا الحقل ليس مطلوب, ولكن هذا يستطيع مساعدة قاعدة معطياتك لان تعمل بشكل متجانس مع اطار عمل اندرويد.

على سبيل المثال, المقطع ادناه يعرف اسم جدول واسماء اعمده لجدول واحد.

public static abstract class FeedEntry implements BaseColumns {
public static final String TABLE_NAME = “entry”;
public static final String COLUMN_NAME_ENTRY_ID = “entryid”;
public static final String COLUMN_NAME_TITLE = “title”;
public static final String COLUMN_NAME_SUBTITLE = “subtitle”;

}

لكي تمنع أي شخص من ان يقوم باستنساخ contract class بشكل عرضي, نقوم بإعطائه باني فارغ.

// Prevents the FeedReaderContract class from being instantiated.
private FeedReaderContract() {}

انشاء قاعدة معطيات عبر استخدام SQL Helper

ما إن تقرر كيف ستبدو قاعدة معطياتك , فإنه يتوجب عليك عندها تحقيق implement التوابع التي تقوم بإنشاء وحفظ قاعدة المعطيات والجداول. فيما يلي بعض العبارات القياسية التي تقوم بإنشاء وحذف جدول:

 

private static final String TEXT_TYPE = ” TEXT”;
private static final String COMMA_SEP = “,”;
private static final String SQL_CREATE_ENTRIES =
“CREATE TABLE ” + FeedReaderContract.FeedEntry.TABLE_NAME + ” (” +
FeedReaderContract.FeedEntry._ID + ” INTEGER PRIMARY KEY,” +
FeedReaderContract.FeedEntry.COLUMN_NAME_ENTRY_ID + TEXT_TYPE + COMMA_SEP +
FeedReaderContract.FeedEntry.COLUMN_NAME_TITLE + TEXT_TYPE + COMMA_SEP +
… // Any other options for the CREATE command
” )”;

private static final String SQL_DELETE_ENTRIES =
“DROP TABLE IF EXISTS ” + TABLE_NAME_ENTRIES;

بشكل مشابه للملفات التي نخزنها على تخزين الداخلي internal storage, فإن اندرويد يقوم بخزن قاعدة المعطيات التي تقوم بإنشائها على على مساحة قرص خاصة مرتبطة بتطبيقك. وتعتبر معطياتك آمنة, لأنه – وبشكل افتراضي- المكان الذي يتم حفظ قاعدة المعطيات فيه غير قابل للنفاذ من قبل بقية التطبيقات.

هنالك مجموعة مفيدة من واجهات التطبيقات البرمجية APIs متوافرة في صف SQLiteOpenHelper. عندما تستخدم هذا الصف للحصول على مرجع إلى قاعدة معطياتك,فإن النظام يقوم بإنجاز العمليات – التي من المحتمل أن تستغرق وقت طويل – الخاصة بإنشاء وتحديث قاعدة المطيات فقط عندما الحاجة وليس خلال مرحلة startup الخاصة بالتطبيق. كل ما أنت بحاجة لفعله هو استدعاء التابع getWritableDatabase()أو التابع getReadableDatabase().

 ملاحظة : لأن تلك العمليات قد تستغرق وقت طويل, تأكد من ان تقوم باستدعاء أي من التابعين getWritableDatabase() أو getReadableDatabase()في مجرى خلفي background thread, مثل ذلك الذي نحصل عليه مع AsyncTask  أو IntentService.

 لكي تستخدم SQLiteOpenHelper, قم بإنشاء صف فرعي يقوم ب override لتوابع الاستدعاء التالية  onCreate(),onUpgrade()و onOpen(). قد ترغب ايضا بالقيام بتنجيز Implemnet الواجهة التالية onDowngrade(), ولكن هذا العمل ليس مطلوبا او ضروريا.

على سبيل المثال, فيما يلي تحقيق implementation للصف SQLiteOpenHelper  والذي يستخدم بعض الاوامر الموضحة اعلاه:

public class FeedReaderDbHelper extends SQLiteOpenHelper {
// If you change the database schema, you must increment the database version.

public static final int DATABASE_VERSION = 1;
public static final String DATABASE_NAME = “FeedReader.db”;

public FeedReaderDbHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
public void onCreate(SQLiteDatabase db) {
db.execSQL(SQL_CREATE_ENTRIES);
}
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// This database is only a cache for online data, so its upgrade policy is
// to simply to discard the data and start over
db.execSQL(SQL_DELETE_ENTRIES);
onCreate(db);
}
public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
onUpgrade(db, oldVersion, newVersion);
}
}

لكي تستطيع النفاذ إلى قاعدة المعطيات, قم باستنساخ الصف الفرعي SQLiteOpenHelper:

FeedReaderDbHelper mDbHelper = new FeedReaderDbHelper(getContext());

وضع المعلومات ضمن قاعدة المعطيات Put Information into a Database

يتم ادخال المعلومات insert ضمن قاعدة المعطيات عبر تمرير غرض ContentValues  إلى التابع insert():

// Gets the data repository in write mode
SQLiteDatabase db = mDbHelper.getWritableDatabase();

// Create a new map of values, where column names are the keys
ContentValues values = new ContentValues();
values.put(FeedReaderContract.FeedEntry.COLUMN_NAME_ENTRY_ID, id);
values.put(FeedReaderContract.FeedEntry.COLUMN_NAME_TITLE, title);
values.put(FeedReaderContract.FeedEntry.COLUMN_NAME_CONTENT, content);

// Insert the new row, returning the primary key value of the new row
long newRowId;
newRowId = db.insert(
FeedReaderContract.FeedEntry.TABLE_NAME,
FeedReaderContract.FeedEntry.COLUMN_NAME_NULLABLE,
values);

إن اول معامل لتابع insert()عبارة عن اسم الجدول table name.اما المعامل الثاني فيزود باسم العمود الذي يستطيع اطار العمل ان يدخل فيه null في حال كان ContentValues  فارغة (في حال قمت باسناد القيمة في هذا المعامل إلى “null”, عندها لن يقوم اطار العمل باضافة السطر عندما لا يكون هنالك قيم).

قراءة المعلومات من قاعدة المعطيات Read Information form a Database

لكي تقرأ المعلومات من قاعدة المعطيات, استخدم تابع query(), مرر له خصايص الاختيار التي تريد والاعمدة المطلوبة.

يتم اعادة نتائج الاستعلام إلى غرض Cursor  :

SQLiteDatabase db = mDbHelper.getReadableDatabase();

// Define a projection that specifies which columns from the database
// you will actually use after this query.
String[] projection = {
FeedReaderContract.FeedEntry._ID,
FeedReaderContract.FeedEntry.COLUMN_NAME_TITLE,
FeedReaderContract.FeedEntry.COLUMN_NAME_UPDATED,

};

// How you want the results sorted in the resulting Cursor
String sortOrder =
FeedReaderContract.FeedEntry.COLUMN_NAME_UPDATED + ” DESC”;

Cursor c = db.query(
FeedReaderContract.FeedEntry.TABLE_NAME,  // The table to query
projection,                               // The columns to return
selection,                                // The columns for the WHERE clause
selectionArgs,                            // The values for the WHERE clause
null,                                     // don’t group the rows
null,                                     // don’t filter by row groups
sortOrder                                 // The sort order
);

لكي تستطيع رؤية الاسطر ضمن cursor, بإمكانك استخدام احد توابع النتقل move methods  الخاصة بغرض Cursor,  والتي يتوجب عليك دوما استدعاءها قبل ان تبدأ بقراءة القيم.

بشكل عام يجب ان تبدأ باستدعاء التابع moveToFirst(), والذي يقوم بتوضيع “read position” على أول مدخل ضمن النتائج. وبالنسبة لكل سطر, بإمكانك قراءة قيم الاعمدة عبر استدعاء احد توابع get الخاصة ب Cursor, مثل getString()أو getLong().

بالنسبة لكل تابع من توابع ال get هذه, يجب ان تمرر دليل الموضع للعمود المطلوب index position , والذي بإمكانك الحصول عليه عبر استدعاء التابع getColumnIndex()أو التابع getColumnIndexOrThrow().

على سبيل المثال :

cursor.moveToFirst();
long itemId = cursor.getLong(
cursor.getColumnIndexOrThrow(FeedReaderContract.FeedEntry._ID)
);

حذف معلومات من قاعدة المعطيات Delete Information form a Database

لحذف سطر من جدول, عليك ان تحدد خاصية الاختيار selection criteria التي تحدد ذلك السطر.

تزودنا API الخاصة بقاعدة المعطيات بآلية لإنشاء خاصية الاختيار selection criteria  والتي تحمينا من SQL injection.

تقسم تلك الآلية خصائص الاختيار selection specification إلى عبارة الاختيار selection clause و معاملات الاختيار selection arguments. تعرف العبارة selection clause الاعمدة التي نريد الاطلاع عليها, وايضا تمكنك من الجمع بين اختبارات الاعمدة.

المعاملات arguments عبارة عن القيم التي تريد الاختبار نسبة إليها والتي يتم الربط بينها وبين عبارة الاختيار clause.

وبما ان النتيجة لا تتم معاملتها بنفس الطريقة التي تتم فيها معاملة عبارة SQL النظامية, لذلك فهي منيعة ضد SQL injection.

// Define ‘where’ part of query.
String selection = FeedReaderContract.FeedEntry.COLUMN_NAME_ENTRY_ID + ” LIKE ?”;
// Specify arguments in placeholder order.
String[] selelectionArgs = { String.valueOf(rowId) };
// Issue SQL statement.
db.delete(table_name, selection, selectionArgs);

تحديث قاعدة المعطيات Update a Database

عندما ترغب بتعديل مجموعة جزئية من قيم قاعدة المعطيات, يجب عليك استخدام التابع update().

إن عملية التعديل تجمع بين ال syntax قيم المحتويات الخاصة بتابعinsert()  مع syntax الخاص ب where  للتابع delete().

SQLiteDatabase db = mDbHelper.getReadableDatabase();

// New value for one column
ContentValues values = new ContentValues();
values.put(FeedReaderContract.FeedEntry.COLUMN_NAME_TITLE, title);

// Which row to update, based on the ID
String selection = FeedReaderContract.FeedEntry.COLUMN_NAME_ENTRY_ID + ” LIKE ?”;
String[] selelectionArgs = { String.valueOf(rowId) };

int count = db.update(
FeedReaderDbHelper.FeedEntry.TABLE_NAME,
values,
selection,
selectionArgs);

وبذلك نكون قد انتهينا من تقديم شرح بسيط وموجز ومفيد عن حفظ المعطيات

وإلى لقاء جديد مع حلقة جديدة من هذه السلسلة

وإلى ذلك الحين استودعكم الله والسلام عليكم ورحمة الله وبركاته

المصطلح

الترجمة

Thread

مسرب أو مجرى

Implementation

تحقيق او تنجيز

class

صف

, , , , , , , , , , , , , , , , , , , , , ,

  1. أضف تعليقاً

أضف تعليقاً

Please log in using one of these methods to post your comment:

WordPress.com Logo

أنت تعلق بإستخدام حساب WordPress.com. تسجيل خروج   / تغيير )

صورة تويتر

أنت تعلق بإستخدام حساب Twitter. تسجيل خروج   / تغيير )

Facebook photo

أنت تعلق بإستخدام حساب Facebook. تسجيل خروج   / تغيير )

Google+ photo

أنت تعلق بإستخدام حساب Google+. تسجيل خروج   / تغيير )

Connecting to %s

%d مدونون معجبون بهذه: