Insert, Read, Delete & Update في SQLite
يوفر Android طرقًا مختلفة لتخزين البيانات محليًا ، لذا فإن استخدام SQLite هو أحد طرق تخزين البيانات. SQLite هي قاعدة بيانات قاعدة استعلام بنية ، ومن ثم يمكننا القول إنها قاعدة بيانات علاقات. يحتوي نظام التشغيل Android على تطبيقه الخاص لإجراء عمليات CRUD (إنشاء وقراءة وتحديث وحذف) ، لذلك يوفر Android مجموعة من الفئات المتاحة في حزم android.database و android.database.sqlite.
أثناء استخدام SQLite ، يمكن أن تكون هناك طريقتان مختلفتان لإجراء عمليات مختلفة مثل الإنشاء والقراءة والتحديث والحذف. أحدهما يكتب استعلامات خام والآخر يستخدم وظائف ذات معلمات أو يمكننا أن نقول استعلامات ذات معلمات.
Create : يعد إنشاء قاعدة بيانات أمرًا بسيطًا جدًا في نظام Android باستخدام فئة SQLiteOpenHelper. SQLiteOpenHelper هي فئة مجردة مع طريقتين مجردتين onCreate (SQLiteDatabase db) و onUpgrade (SQLiteDatabase db و int oldVersion و int newVersion) والعديد من الوظائف المفيدة لقاعدة البيانات. كلما احتجنا إلى إنشاء قاعدة بيانات ، يتعين علينا توسيع فئة SQLiteOpenHelper على النحو التالي:
/**A helper class to perform database related queries*/ public class SqliteManager extends SQLiteOpenHelper { public static final String DATABASE_NAME = "abhiandroid.db"; public static final int version = 1; public SqliteManager(Context context) { super(context, DATABASE_NAME, null, version); } @Override public void onCreate(SQLiteDatabase sqLiteDatabase) { String dbQuery = "CREATE TABLE Items (id INTEGER PRIMARY KEY AUTOINCREMENT,name TEXT, description TEXT)"; sqLiteDatabase.execSQL(dbQuery); } @Override public void onUpgrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVersion) { } }
يتم استدعاء طريقة
onCreate (SQLiteDatabase sqLiteDatabase)
لمرة واحدة فقط طوال دورة حياة التطبيق ، وسوف يتم استدعاؤها كلما كان هناك أول استدعاء لوظيفة getReadableDatabase () أو getWritableDatabase () المتوفرة في فئة super SQLiteOpenHelper ، لذلك تقوم فئة SQLiteOpenHelper باستدعاء طريقة onCreate () بعد الإنشاء قاعدة بيانات وإنشاء كائن SQLiteDatabase. تم تمرير اسم قاعدة البيانات في استدعاء المُنشئ.
لا يتم استدعاء
onUpgrade (SQLiteDatabase db ، int oldVersion ، int newVersion)
إلا عندما يكون هناك تحديث في الإصدار الحالي ، لذلك لتحديث إصدار ، يتعين علينا زيادة قيمة متغير الإصدار الذي تم تمريره في مُنشئ الفئة الفائقة. في طريقة onUpgrade يمكننا كتابة استعلامات لأداء أي إجراء مطلوب. في معظم الأمثلة ، سترى أنه يتم إسقاط الجدول (الجداول) الموجودة ومرة أخرى يتم استدعاء طريقة onCreate () لإنشاء الجداول مرة أخرى. لكن ليس من الضروري القيام بذلك ، فكل هذا يتوقف على متطلباتك. يتعين علينا تغيير إصدار قاعدة البيانات إذا أضفنا صفًا جديدًا في جدول قاعدة البيانات في هذه الحالة إذا كان لدينا متطلبات لا نريد فقدان البيانات الموجودة في الجدول ، فيمكننا كتابة استعلام جدول بديل في onUpgrade (SQLiteDatabase db ، int oldVersion ، int newVersion) الطريقة.
وبالمثل ، إذا لم تكن هناك متطلبات للبيانات الموجودة كلما قمنا بترقية إصدار قاعدة البيانات ، فيمكننا كتابة استعلام جدول الإسقاط في أسلوب onUpgrade (SQLiteDatabase db ، int oldVersion ، int newVersion) واستدعاء طريقة onCreate (SQLiteDatabase sqLiteDatabase) مرة أخرى لإنشاء الجدول مرة أخرى. تذكر عدم استدعاء أسلوب onCreate (SQLiteDatabase sqLiteDatabase) إذا كنت قد كتبت استعلام جدول بديل في أسلوب onUpgrade (SQLiteDatabase db ، int oldVersion ، int newVersion).
عملية Insert, Read, Delete & Update في Sqlite
لإجراء عملية الإدراج والقراءة والحذف والتحديث ، هناك طريقتان مختلفتان:
- كتابة استعلامات ذات معلمات (مستحسن)
- اكتب استفسارات أولية
استعلامات ذات معلمات: هذه هي تلك الاستعلامات التي يتم إجراؤها باستخدام وظائف داخلية لإدراج البيانات أو قراءتها أو حذفها أو تحديثها. يتم توفير هذه الوظائف المتعلقة بالعملية في فئة SQLiteDatabase.
الاستعلامات الأولية: هذه استعلامات sql بسيطة مشابهة لقواعد البيانات الأخرى مثل MySql و Sql Server وما إلى ذلك ، في هذه الحالة سيتعين على المستخدم كتابة استعلام كنص وتمرير سلسلة الاستعلام في rawQuery (String sql أو String [] selectArgs) أو execSQL (سلسلة) sql ، كائن [] bindArgs) لإجراء العمليات.
ملاحظة مهمة: لا توصي وثائق Android باستخدام الاستعلامات الأولية لإجراء عمليات الإدراج ، والقراءة ، والتحديث ، والحذف ، واستخدام وظائف إدراج فئة SQLiteDatabase واستعلامها وتحديثها وحذفها دائمًا.
فيما يلي مثال على الاستعلام الأولي لإدخال البيانات:
public void insertItem(Item item) { String query = "INSERT INTO " + ItemTable.NAME + " VALUES (0,?,?)"; SQLiteDatabase db = getWritableDatabase(); db.execSQL(query, new String[]{item.name, item.description}); db.close(); }
أثناء استخدام الاستعلامات الأولية ، لم نتوصل أبدًا إلى معرفة نتيجة العملية ، ولكن مع وظيفة الاستعلامات ذات المعلمات ، يتم إرجاع قيمة لنجاح العملية أو فشلها.
Insert : لإجراء عملية الاضافه باستخدام استعلام ذي معلمات ، يتعين علينا استدعاء وظيفة الإدراج المتوفرة في فئة SQLiteDatabase. تحتوي وظيفة insert () على ثلاث معلمات مثل الإدراج العام الطويل (String tableName ، String nullColumnHack ، قيم ContentValues) حيث يكون اسم الجدول هو اسم الجدول الذي سيتم إدراج البيانات فيه.
public long insert(String tableName,String nullColumnHack,ContentValues values)
قد يتم تمرير NullColumnHack فارغًا ، فهو يتطلب قيمة عمود الجدول في حالة عدم وضع اسم العمود في كائن ContentValues لذلك يجب إدراج قيمة فارغة لهذا العمود المحدد ، والقيم هي تلك القيم التي يجب إدراجها- ContentValues هي مفتاح- كائن قائم على الزوج يقبل جميع قيم النوع البدائي ، لذلك عندما يتم وضع البيانات في كائن ContentValues ، يجب وضعها مرة أخرى اسم عمود الجدول كمفتاح والبيانات كقيمة. تُرجع الدالة insert قيمة طويلة ، أي رقم الصف المُدرج إذا تم إدراجه بنجاح ، - 1 بخلاف ذلك.
هنا مثال بسيط:
//Item is a class representing any item with id, name and description. public void addItem(Item item) { SQLiteDatabase db = getWritableDatabase(); ContentValues contentValues = new ContentValues(); contentValues.put("name",item.name); // name - column contentValues.put("description",item.description); // description is column in items table, item.description has value for description db.insert("Items", null, contentValues);//Items is table name db.close(); }
Update : وظيفة التحديث مشابهة تمامًا للإدراج ولكنها تتطلب معلمتين إضافيتين ، فهي لا تتطلب nullColumnHack. يحتوي على أربع معلمات إجمالاً ، وهما متشابهة لإدراج وظيفة هي اسم الجدول وقيم المحتوى. اثنان آخران هما whereClause (String) و whereArgs (String []).
تتوفر وظيفة التحديث في فئة SQLiteDatabase وهي تبدو كما يلي:
public int update(String tableName,ContentValues contentValues,String whereClause,String[] whereArgs)
هنا حيث حيث يتم إخبار قاعدة البيانات بمكان تحديث البيانات في الجدول ، يوصى بتمرير (الأسئلة) مع اسم العمود في whereClause String. وبالمثل ، حيث ستحتوي مصفوفة Args على قيم لتلك الأعمدة التي تم وضع "ق" مقابلها في whereClause. ستعيد وظيفة التحديث عدد الصفوف المتأثرة إذا نجحت ، 0 وإلا.
هنا استخدام بسيط للتحديث:
//Item is a class representing any item with id, name and description public void updateItem(Item item) { SQLiteDatabase db = getWritableDatabase(); ContentValues contentValues = new ContentValues(); contentValues.put("id", item.id); contentValues.put("name", item.name); contentValues.put("description", item.description); String whereClause = "id=?"; String whereArgs[] = {item.id.toString()}; db.update("Items", contentValues, whereClause, whereArgs); }
Delete : على غرار الإدراج والتحديث ، تتوفر وظيفة الحذف في فئة SQLiteDatabase ، لذا فإن الحذف يشبه إلى حد كبير تحديث الوظيفة بصرف النظر عن كائن ContentValues لأنه غير مطلوب في الحذف. public int delete (String tableName، String whereClause، String [] whereArgs) تحتوي على ثلاث معلمات تشبه تمامًا معلمات وظيفة التحديث وتستخدم بنفس الطريقة كما في وظيفة التحديث.
هنا استخدام بسيط للحذف:
public void deleteItem(Item item) { SQLiteDatabase db = getWritableDatabase(); String whereClause = "id=?"; String whereArgs[] = {item.id.toString()}; db.delete("Items", whereClause, whereArgs); }
هنا حيث يكون السبب اختياريًا ، سيؤدي تمرير القيمة الفارغة إلى حذف جميع الصفوف في الجدول. ستعيد وظيفة الحذف رقم الصف المتأثر إذا تم تمرير الشرط الذي تم تمريره بخلاف ذلك سيعود 0.
ملاحظة مهمة: إذا كنت تريد إزالة جميع الصفوف وتطلب عدد الصفوف المحذوفة ، فقم بتمرير 1 كـ whereClause .
قراءة (select): تختلف القراءة من جدول قاعدة البيانات قليلاً عن الوظائف الأخرى مثل الإدراج والتحديث والحذف. توفر فئة SQLiteDatabaseطريقة استعلام () لقراءة البيانات من الجدول. طريقة الاستعلام () محملة بشكل زائد بمجموعة مختلفة من المعلمات. تقوم بإرجاعكائن المؤشر ، لذا فإن المؤشر عبارة عن مجموعة نتائج تحتوي على بيانات تم الاستعلام عنها ، ويوفر وظائف مختلفة مفيدة حقًا أثناء قراءة البيانات.
فيما يلي بعض وظائف الاستعلام المحملة بشكل زائد:
- public Cursor query (String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit)
- public Cursor query (String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy)
- public Cursor query (boolean distinct, String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy, String limit)
معظم المعلمات في وظائف الاستعلام المحملة بشكل زائد اختيارية باستثناء من الجدول ويمكن تمرير أي من المعلمات الأخرى على أنها خالية. إذا تم تمرير علامة مميزة على أنها مجموعة بيانات المؤشر الحقيقية فلن تحتوي على أي صف مكرر.
public ArrayList<Item> readAllItems() { ArrayList<Item> items = new ArrayList<>(); SQLiteDatabase db = getReadableDatabase(); //see above point 2 function Cursor cursor = db.query("Items" , null// columns - null will give all , null// selection , null// selection arguments , null// groupBy , null// having , null// no need or order by for now; if (cursor != null) { while (cursor.moveToNext()) { // move the cursor to next row if there is any to read it's data Item item = readItem(cursor); items.add(item); } } return items; } private Item readItem(Cursor cursor) { Item item = new Item(); item.id = cursor.getInt(cursor.getColumnIndex(ItemTable.COL_ID)); item.name = cursor.getString(cursor.getColumnIndex(ItemTable.COL_NAME)); item.description = cursor.getString(cursor.getColumnIndex(ItemTable.COL_DESCRIPTION)); return item; }
طريقة إضافة واسترجاع صورة من قاعدة بيانات SQLite
سنناقش الآن كيفية إضافة أو استرداد الصورة من وحدة التخزين الخارجية للهاتف إلى التطبيق باستخدام قاعدة بيانات SQLite. نقوم في الأساس بإنشاء قاعدة بيانات وجدول في التطبيق باستخدام SQLite. سيحتوي الجدول على الصورة التي تم جلبها من وحدة التخزين الخارجية.
يوجد اختلاف أثناء الاسترداد بمستوى API مختلف. تم تغيير مفهوم الإذن منذ API 23. قبل مستوى API 23 ، سُئل المستخدم أثناء التثبيت وبعد مستوى API 23 يُطلب من المستخدم أثناء وقت التشغيل. لذلك ، تمت إضافة إذن وقت تشغيل إضافي في التطبيق الذي يعمل على مستوى API أعلى من 23.
فيما يلي شرح للطريقتين خطوة بخطوة لإضافة أو استرداد صورة من قاعدة بيانات SQLite.
مثال 1: إضافة واسترجاع الصورة من قاعدة بيانات SQLite (أقل من مستوى API 23)
في هذا المثال ، استخدمنا الأزرار و imageview لإنشاء واجهة المستخدم ، تتم إضافة الزر عند النقر ويتم تحديد الطرق في فئة جافا المقابلة.
الخطوة 1: قم بإنشاء مشروع جديد وقم بتسميته SqliteImageDemo .
الخطوة 2: افتح ملف AndroidManifest.xml وأضف إذنًا للوصول إلى وحدة التخزين الخارجية.
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
الخطوة 3: افتح res -> layout -> activity_main.xml (أو) main.xml وأضف الكود التالي:
في هذا الكود ، قم ببساطة بإضافة imageeview وزر مع وظيفة onclick.
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="com.example.sqliteimagedemo.MainActivity"> <Button android:text="@string/get_image" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="19dp" android:id="@+id/button" android:layout_alignParentTop="true" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" android:onClick="save"/> <Button android:text="@string/view_image" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="29dp" android:id="@+id/button2" android:layout_below="@+id/button" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" android:onClick="get"/> <ImageView android:layout_width="match_parent" android:layout_height="match_parent" app:srcCompat="@mipmap/ic_launcher" android:id="@+id/imageView" android:layout_below="@+id/button2" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" android:layout_marginTop="43dp" tools:ignore="ContentDescription" /> </RelativeLayout>
الخطوة 4: افتح src -> package -> MainActivity.java
في هذه الخطوة ، نفتح MainActivity ونضيف الوظائف المحددة عبر الزر عند النقر على أي حفظ أو الحصول. تحتوي طريقة الحفظ على FileInputStream للحصول على ملف من المسار المحدد وحفظه في قاعدة البيانات. علاوة على ذلك ، يتم إدراج الصورة في الجدول باستخدام SQLiteDatabase ، ويتم استخدام Toast للإشارة إلى اكتمال العملية. تستخدم طريقة get عبارة تحديد SQLite لاسترداد الصورة المحفوظة وعرضها في imageeview.
package com.example.sqliteimagedemo; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.ImageView; import android.widget.Toast; import java.io.FileInputStream; import java.io.IOException; public class MainActivity extends AppCompatActivity { ImageView imageView; SQLiteDatabase db; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); imageView = (ImageView) findViewById(R.id.imageView); //database created db = this.openOrCreateDatabase("test.db", Context.MODE_PRIVATE,null); //table created db.execSQL("create table if not exists imageTb ( a blob )"); } public void save(View view) throws IOException { FileInputStream fis = new FileInputStream("/storage/sdcard/demoImage.jpg"); byte[] image= new byte[fis.available()]; fis.read(image); ContentValues values = new ContentValues(); values.put("a",image); db.insert("imageTb", null,values); fis.close(); Toast.makeText(this,"Done", Toast.LENGTH_SHORT).show(); } public void get(View view) { Cursor c = db.rawQuery("select * from imageTb", null); if(c.moveToNext()) { byte[] image = c.getBlob(0); Bitmap bmp= BitmapFactory.decodeByteArray(image, 0 , image.length); imageView.setImageBitmap(bmp); Toast.makeText(this,"Done", Toast.LENGTH_SHORT).show(); } } }
المخرجات :
الآن قم بتشغيل التطبيق وانقر فوق الزر لإضافة واسترداد الصورة في التطبيق.
مثال 2: إضافة واسترجاع صورة من قاعدة بيانات SQLite (أعلى مستوى API 23)
في هذا المثال ، استخدمنا الأزرار و imageview لإنشاء واجهة المستخدم ، تتم إضافة الزر عند النقر ويتم تحديد الطرق في فئة جافا المقابلة. الاختلاف الأساسي هو أننا نحتاج إلى تحديد الأذونات في وقت التشغيل.
الخطوة 1: قم بإنشاء مشروع جديد وقم بتسميته SqliteImageDemo .
الخطوة 2: افتح ملف AndroidManifest.xml وأضف إذنًا للوصول إلى وحدة التخزين الخارجية.
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
الخطوة 3: افتح res -> layout -> activity_main.xml (أو) main.xml وأضف الكود التالي:
في هذا الكود ، أضف ببساطة imageview وزرًا بوظيفة onclick.
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="com.example.sqliteimagedemo.MainActivity"> <ImageView android:layout_width="match_parent" android:layout_height="match_parent" app:srcCompat="@mipmap/ic_launcher" android:layout_marginTop="61dp" android:id="@+id/imageView" android:layout_below="@+id/button1" android:layout_alignLeft="@+id/button1" android:layout_alignStart="@+id/button1" /> <Button android:text="VIEW FETCHED IMAGE" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/button2" android:onClick="viewImage" android:layout_below="@+id/button1" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" /> <Button android:text="FETCH IMAGE FROM EXTERNAL STORAGE" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/button1" android:onClick="fetchImage" android:layout_alignParentTop="true" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" /> </RelativeLayout>
الخطوة 4: افتح src -> package -> MainActivity.java
في هذه الخطوة ، نفتح MainActivity ونضيف الوظائف المحددة عبر الزر عند النقر على أي حفظ أو الحصول. تحتوي طريقة الحفظ على FileInputStream للحصول على ملف من المسار المحدد وحفظه في قاعدة البيانات. علاوة على ذلك ، يتم إدراج الصورة في الجدول باستخدام SQLiteDatabase ، ويتم استخدام Toast للإشارة إلى اكتمال العملية. تستخدم طريقة get عبارة تحديد SQLite لاسترداد الصورة المحفوظة وعرضها في imageeview.
بالإضافة إلى واجهة برمجة التطبيقات السابقة ، تتم إضافة بيان يمثل في الأساس إذنًا لقراءة / كتابة وحدة التخزين الخارجية.
package com.example.sqliteimagedemo; import android.Manifest; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Environment; import android.support.v4.app.ActivityCompat; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.ImageView; import android.widget.Toast; import java.io.File; import java.io.FileInputStream; import java.io.IOException; public class MainActivity extends AppCompatActivity { private int STORAGE_PERMISSION_CODE = 23; ImageView imageView; SQLiteDatabase db; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //Permission to access external storage ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},STORAGE_PERMISSION_CODE); imageView = (ImageView) findViewById(R.id.imageView); //creating database db = this.openOrCreateDatabase("test.db", Context.MODE_PRIVATE,null); //creating table for storing image db.execSQL("create table if not exists imageTb ( image blob )"); } public void viewImage(View view) { Cursor c = db.rawQuery("select * from imageTb", null); if(c.moveToNext()) { byte[] image = c.getBlob(0); Bitmap bmp= BitmapFactory.decodeByteArray(image, 0 , image.length); imageView.setImageBitmap(bmp); Toast.makeText(this,"Done", Toast.LENGTH_SHORT).show(); } } public void fetchImage(View view) throws IOException { File folder= new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) + "/demoImage.jpg/"); FileInputStream fis = new FileInputStream(folder); byte[] image= new byte[fis.available()]; fis.read(image); ContentValues values = new ContentValues(); values.put("image",image); db.insert("imageTb", null,values); fis.close(); Toast.makeText(this,"Image Fetched", Toast.LENGTH_SHORT).show(); } }
المخرج :
الآن قم بتشغيل التطبيق وانقر فوق الزر لإضافة واسترداد الصورة في التطبيق.