Android Programlama Ders 42: SQLite’ta Veri Tabanı Güncelliyoruz

In Makale, Mobil, Pratik by Victor CuiumjuLeave a Comment

Android Programlama Ders 42′de onUpgrade metodunu kullanarak SQLite’ta veri tabanı güncellemeyi öğreneceğiz.

Uygulama geliştirirken zaman zaman veri tabanını güncelleme ihtiyacı oluşabiliyor. Geçen derslerde SQLiteOpenHelper klasının onUpgrade metodundan bahsettim. onUpgrade metodu, var olan veri tabanı bağlanmak istediğimiz veri tabanından farklıysa çağrılıyor.

onUpgrade kullanarak veri tabanının yeni versiyona geçişi araştıralım. Bunu yapmak için küçük bir uygulama oluşturalım. Uygulama geçen derslerde yaptığımız “çalışanlar ve meslekleri” konulu olacak.

Birinci versiyonda veri tabanımız sadece people (insanlar) tablosunu içerecek. Tablomuzun iki sütunu çalışanların isim ve mesleğini taşıyacak. Bu tablo pek kullanışlı değil, çünkü mesleğin ismi değiştiği zaman people tablosundaki tüm kayıtların güncellenmesi gerekecektir. Bu yüzden veri tabanında verinin yapısını değiştirmeye karar veriyoruz.

İkinci versiyonda yeni tabloyu position (meslek) ekleyeceğiz. Position tablomuz iki sütundan (meslek ismi ve maaş) oluşacak. People tablosunda insanların mesleği yerinde position tablodan ID’sini kullanacağız

Projeyi oluşturalım:

  • Project name: P0042_SQLiteOnUpgrade
  • Build Target: Android 4.2
  • Application name: SQLiteOnUpgrade
  • Package name: tr.example.sqliteonupgrade
  • Create Activity: MainActivity

Ekranı kullanmayacağız tüm sonuçları bildirime yazdıracağız.

MainActivity.java oluşturalım:

import android.app.Activity;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.os.Bundle;
import android.util.Log;
 
public class MainActivity extends Activity {
 
final String LOG_TAG = "myLogs";

 
final String DB_NAME = "staff"; // veri tabanin ismi

finalintDB_VERSION = 1; // versiyonu
 

/** Called when the activity is first created. */

@Override

public void onCreate(Bundle savedInstanceState) {
 
   super.onCreate(savedInstanceState);

   setContentView(R.layout.main);

    DBHelper dbh = new DBHelper(this);

   SQLiteDatabase db = dbh.getWritableDatabase();

    Log.d(LOG_TAG, " --- Staff db v." + db.getVersion() + " --- ");

   writeStaff(db);

   dbh.close();

}
 

// kayitlari bildirime yazdiriyoruz

private void writeStaff(SQLiteDatabase db) {

   Cursor c = db.rawQuery("select * from people", null);

   logCursor(c, "Table people");

   c.close();

}

 
// kursordan kayitlari bildirime yazdiriyoruz

void logCursor(Cursor c, String title) {

   if (c != null) {

     if (c.moveToFirst()) {

   Log.d(LOG_TAG, title + ". " + c.getCount() + " rows");

       StringBuilder sb = new StringBuilder();

       do {

         sb.setLength(0);

         for (String cn : c.getColumnNames()) {

           sb.append(cn + " = "

               + c.getString(c.getColumnIndex(cn)) + "; ");

         }

    Log.d(LOG_TAG, sb.toString());

       } while (c.moveToNext());

     }

   } else

   Log.d(LOG_TAG, title + ". Cursor is null");

}

    class DBHelper extends SQLiteOpenHelper {

    public DBHelper(Context context) {

     super(context, DB_NAME, null, DB_VERSION);

   }

    public void onCreate(SQLiteDatabase db) {

    Log.d(LOG_TAG, " --- onCreate database --- ");
 

     String[] people_name = {"Ahmet", "Seyda", "Ali", "Omer", "Sevgi", "Umut", "Murat", "Mehmet"};

     String[] people_positions = {"Programci", "Muhasebeci", "Programci", "Programci", "Muhasebeci", "Mudur","Programci", "Guvenlik" };

     ContentValues cv = new ContentValues();

      // people tabolyu olusturuyoruz

     db.execSQL("create table people ("

         + "id integer primary key autoincrement,"

         + "name text, position text);");

      // dolduruyoruz

     for (int i = 0; i < people_name.length; i++) {

       cv.clear();

       cv.put("name", people_name[i]);

       cv.put("position", people_positions[i]);

       db.insert("people", null, cv);

     }

   }

   public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    }

}

}

Yukarıdaki verdiğim kodu inceleyelim.

logCursor metodu kullanarak Cursor’dan kayıtları bildirime yazdırıyoruz. writeStaff metodu kayıtları people tablosundan seçiyor ve logCursor metodunu çağırıyor. Activity onCreate metodunda DBHelper nesneyi oluşturuyoruz ve veri tabanına bağlıyoruz. Sonra veri tabanının versiyonu bildirime yazdırıyoruz, writeStaff metodu çağırıyoruz ve bağlantıyı kapatıyoruz. onCreate metodunda tabloyu oluşturuyoruz ve dolduruyoruz.

Kaydedelim ve uygulamayı çalıştıralım.

Bildirimlere bakalım:

— onCreate database —
— Staff db v.1 —
Table people. 8 rows
id = 1; name = Ahmet; position = Programci;
id = 2; name = Seyda; position = Muhasebeci;
id = 3; name = Ali; position = Programci;
id = 4; name = Omer; position = Programci;
id = 5; name = Sevgi; position = Muhasebeci;
id = 6; name = Umut; position = Mudur;
id = 7; name = Murat; position = Programci;
id = 8; name = Mehmet; position = Guvenlik;

Uygulamamız problemsiz çalışıyor. Tablonun kayıtlarını bildirimlere görebiliriz. Şimdi versiyonu güncellemek için bir planı oluşturalım.

Planımız:

–         position tabloyu oluşturuyoruz ve dolduruyoruz

–         position tablosundan id kaydetmek için people tabloya posid sütunu ekliyoruz

–         people.position değerlerine göre people.posid dolduruyoruz

–         people.position sütununu siliyoruz

MainActivity.java’yı değiştirelim. Uygulamamızın veri tabanı versiyonu eşittir iki olacak. DB_VERSION = 2’ye değiştiriyoruz.

   final int DB_VERSION = 2; // veri tabanin versiyonu

writeStaff metodu değiştiriyoruz:

 private void writeStaff(SQLiteDatabase db) {
       Cursor c = db.rawQuery("select * from people", null);
       logCursor(c, "Table people");
       c.close();

       c = db.rawQuery("select * from position", null);
       logCursor(c, "Table position");
       c.close();

       String sqlQuery = "select PL.name as Name, PS.name as Position, salary as Salary "
         + "from people as PL "
         + "inner join position as PS "
         + "on PL.posid = PS.id ";
       c = db.rawQuery(sqlQuery, null);
       logCursor(c, "inner join");
       c.close();
   }

Bildirimlere people, position ve tabloların birleşimini yazdıracağız.

DBHelper’de onUpgrade metodu gerçekleştireceğiz:

public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
      Log.d(LOG_TAG, " --- onUpgrade database from " + oldVersion
          + " to " + newVersion + " version --- ");

      if (oldVersion == 1 && newVersion == 2) {

        ContentValues cv = new ContentValues();

        // position tablo icin veriler
        int[] position_id = { 1, 2, 3, 4 };
        String[] position_name = { "Mudur", "Programci",
            "Muhasebeci", "Guvenlik" };
        int[] position_salary = { 15000, 13000, 10000, 8000 };

        db.beginTransaction();
        try {
          // position tabloyu olusturuyoruz
          db.execSQL("create table position ("
              + "id integer primary key,"
              + "name text, salary integer);");

          // dolduruyoruz
          for (int i = 0; i < position_id.length; i++) {
            cv.clear();
            cv.put("id", position_id[i]);
            cv.put("name", position_name[i]);
            cv.put("salary", position_salary[i]);
            db.insert("position", null, cv);
          }

          db.execSQL("alter table people add column posid integer;");

          for (int i = 0; i < position_id.length; i++) {
            cv.clear();
            cv.put("posid", position_id[i]);
            db.update("people", cv, "position = ?",
                new String[] { position_name[i] });
          }

          db.execSQL("create temporary table people_tmp ("
              + "id integer, name text, position text, posid integer);");

          db.execSQL("insert into people_tmp select id, name, position, posid from people;");
          db.execSQL("drop table people;");

          db.execSQL("create table people ("
              + "id integer primary key autoincrement,"
              + "name text, posid integer);");

          db.execSQL("insert into people select id, name, posid from people_tmp;");
          db.execSQL("drop table people_tmp;");

          db.setTransactionSuccessful();
        } finally {
          db.endTransaction();
        }
      }
    }

  }
}

Yukarıdaki kodda transaction (işlem) kullanıyoruz. Amacımız veri tabanında güncelleme olduğu zaman eğer hata olduysa tüm değişikliklerin iptal olmasıdır. Bu durumlarda transaction çok faydalı oluyor.

İkinci önemli olay, güncelleme yaptığımız zaman geçici tabloyu oluşturmamız gerekiyor. Geçici tabloya kayıtları kopyalıyoruz. Sonraki aşamada eski tabloyu yok ediyoruz ve yeni güncellenmiş tabloyu oluşturuyoruz. Son aşamada geçici tablodan kayıtları kopyalıyoruz ve geçici tabloyu yok ediyoruz. Ayrıntılı bilgi almak için bu linkten faydalanabilirsiniz – How do I add or delete columns from an existing table in SQLite.

Uygulamamız güncellendi. Uygulamayı çalıştırdığımız zaman veri tabanına bağlanacak, versiyon değişeceğini fark edecek ve onUpgrade metodu çağıracak. Kullanıcı uygulamayı ilk defa çalıştırıyor olabilir. Bu durumda uygulama veri tabanını ilk defa oluşturacak ve versiyon numarası eşittir iki olacak. Veri tabanını DBHelper klasta onCreate metodunda oluşturuyoruz. Bu demektir ki ikinci versiyonu oluşturmak için onCreate metodunu değiştirmemiz gerekiyor.

onCreate metodu oluşturalım:

   public void onCreate(SQLiteDatabase db) {
      Log.d(LOG_TAG, " --- onCreate database --- ");

      String[] people_name = { "Ahmet", "Seyda", "Ali", "Omer", "Sevgi", "Umut", "Murat", "Mehmet" };
      int[] people_posid = { 2, 3, 2, 2, 3, 1, 2, 4 };

      // position tablo icin veriler
      int[] position_id = { 1, 2, 3, 4 };
      String[] position_name = { "Mudur", "Programci", "Muhasebeci",
          "Guvenlik" };
      int[] position_salary = { 15000, 13000, 10000, 8000 };

      ContentValues cv = new ContentValues();

      // position tabloyu olusturuyoruz
      db.execSQL("create table position (" + "id integer primary key,"
          + "name text, salary integer" + ");");

      // dolduruyoruz
      for (int i = 0; i < position_id.length; i++) {
        cv.clear();
        cv.put("id", position_id[i]);
        cv.put("name", position_name[i]);
        cv.put("salary", position_salary[i]);
        db.insert("position", null, cv);
      }

      // people tabloyu olusturuyoruz
      db.execSQL("create table people ("
          + "id integer primary key autoincrement,"
          + "name text, posid integer);");

      // dolduruyoruz
      for (int i = 0; i < people_name.length; i++) {
        cv.clear();
        cv.put("name", people_name[i]);
        cv.put("posid", people_posid[i]);
        db.insert("people", null, cv);
      }
    }

Yukarıdaki kodda tabloları oluşturuyoruz ve dolduruyoruz. Şimdi uygulamayı kaydedelim ve çalıştıralım.

Bildirimlere bakıyoruz:

— onUpgrade database from 1 to 2 version —

— Staff db v.2 —

Table people. 8 rows

id = 1; name = Ahmet; posid = 2;

id = 2; name = Seyda; posid = 3;

id = 3; name = Ali; posid = 2;

id = 4; name = Omer; posid = 2;

id = 5; name = Sevgi; posid = 3;

id = 6; name = Umut; posid = 1;

id = 7; name = Murat; posid = 2;

id = 8; name = Mehmet; posid = 4;

Table position. 4 rows

id = 1; name = Mudur; salary = 15000;

id = 2; name = Programci; salary = 13000;

id = 3; name = Muhasebeci; salary = 10000;

id = 4; name = Guvenlik; salary = 8000;

inner join. 8 rows

Name = Ahmet; Position = Programci; Salary = 13000;

Name = Seyda; Position = Muhasebeci; Salary = 10000;

Name = Ali; Position = Programci; Salary = 13000;

Name = Omer; Position = Programci; Salary = 13000;

Name = Sevgi; Position = Muhasebeci; Salary = 10000;

Name = Umut; Position = Mudur; Salary = 15000;

Name = Murat; Position = Programci; Salary = 13000;

Name = Mehmet; Position = Guvenlik; Salary = 8000;

onUpgrade metodunun çağırmasını görüyoruz. Veri tabanımız güncellendi ve ilk versiyondan ikinciye geçti. Güncellemenin başarılı olduğunu kontrol etmek için kayıtları bildirimlere yazdırıyoruz. onCreate metodunun çalışıp çalışmadığını kontrol etmek için veri tabanından dosyayı sileceksiniz ve uygulamayı yeniden çalıştıracaksınız. Uygulama çalıştığı zaman veri tabanını bulamayacak ve yeniden oluşturacak (Versiyon = 2).

MainActivity.java tam kodu:

 import android.app.Activity;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.os.Bundle;
import android.util.Log;

public class MainActivity extends Activity {

  final String LOG_TAG = "myLogs";

  final String DB_NAME = "staff"; // veri tabanin ismi
  final int DB_VERSION = 2; // versiyonu

  /** Called when the activity is first created. */
  @Override
  public void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    DBHelper dbh = new DBHelper(this);
    SQLiteDatabase db = dbh.getWritableDatabase();
    Log.d(LOG_TAG, " --- Staff db v." + db.getVersion() + " --- ");
    writeStaff(db);
    dbh.close();
  }

  // verileri sorguluyoruz ve bildirimlere yazdiriyoruz
  private void writeStaff(SQLiteDatabase db) {
    Cursor c = db.rawQuery("select * from people", null);
    logCursor(c, "Table people");
    c.close();

    c = db.rawQuery("select * from position", null);
    logCursor(c, "Table position");
    c.close();

    String sqlQuery = "select PL.name as Name, PS.name as Position, salary as Salary "
        + "from people as PL "
        + "inner join position as PS "
        + "on PL.posid = PS.id ";
    c = db.rawQuery(sqlQuery, null);
    logCursor(c, "inner join");
    c.close();
  }

  // kursordan verileri bildirimlere yazdiriyoruz
  void logCursor(Cursor c, String title) {
    if (c != null) {
      if (c.moveToFirst()) {
        Log.d(LOG_TAG, title + ". " + c.getCount() + " rows");
        StringBuilder sb = new StringBuilder();
        do {
          sb.setLength(0);
          for (String cn : c.getColumnNames()) {
            sb.append(cn + " = "
                + c.getString(c.getColumnIndex(cn)) + "; ");
          }
          Log.d(LOG_TAG, sb.toString());
        } while (c.moveToNext());
      }
    } else
      Log.d(LOG_TAG, title + ". Cursor is null");
  }

  class DBHelper extends SQLiteOpenHelper {

    public DBHelper(Context context) {
      super(context, DB_NAME, null, DB_VERSION);
    }

    public void onCreate(SQLiteDatabase db) {
      Log.d(LOG_TAG, " --- onCreate database --- ");

      String[] people_name = { "Ahmet", "Seyda", "Ali", "Omer", "Sevgi", "Umut", "Murat", "Mehmet" };
      int[] people_posid = { 2, 3, 2, 2, 3, 1, 2, 4 };

      // position tablo icin veriler
      int[] position_id = { 1, 2, 3, 4 };
      String[] position_name = { "Mudur", "Programci", "Muhasebeci",
          "Guvenlik" };
      int[] position_salary = { 15000, 13000, 10000, 8000 };

      ContentValues cv = new ContentValues();

      // position tabloyu olusturuyoruz
      db.execSQL("create table position (" + "id integer primary key,"
          + "name text, salary integer" + ");");

      // dolduruyoruz
      for (int i = 0; i < position_id.length; i++) {
        cv.clear();
        cv.put("id", position_id[i]);
        cv.put("name", position_name[i]);
        cv.put("salary", position_salary[i]);
        db.insert("position", null, cv);
      }

      // people tabloyu olusturuyoruz
      db.execSQL("create table people ("
          + "id integer primary key autoincrement,"
          + "name text, posid integer);");

      // dolduruyoruz
      for (int i = 0; i < people_name.length; i++) {
        cv.clear();
        cv.put("name", people_name[i]);
        cv.put("posid", people_posid[i]);
        db.insert("people", null, cv);
      }
    }

    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
      Log.d(LOG_TAG, " --- onUpgrade database from " + oldVersion
          + " to " + newVersion + " version --- ");

      if (oldVersion == 1 && newVersion == 2) {

        ContentValues cv = new ContentValues();

        // position tablo icin veriler
        int[] position_id = { 1, 2, 3, 4 };
        String[] position_name = { "Mudur", "Programci",
            "Muhasebeci", "Guvenlik" };
        int[] position_salary = { 15000, 13000, 10000, 8000 };

        db.beginTransaction();
        try {
          // position tabloyu olusturuyoruz
          db.execSQL("create table position ("
              + "id integer primary key,"
              + "name text, salary integer);");

          // dolduruyoruz
          for (int i = 0; i < position_id.length; i++) {
            cv.clear();
            cv.put("id", position_id[i]);
            cv.put("name", position_name[i]);
            cv.put("salary", position_salary[i]);
            db.insert("position", null, cv);
          }

          db.execSQL("alter table people add column posid integer;");

          for (int i = 0; i < position_id.length; i++) {
            cv.clear();
            cv.put("posid", position_id[i]);
            db.update("people", cv, "position = ?",
                new String[] { position_name[i] });
          }

          db.execSQL("create temporary table people_tmp ("
              + "id integer, name text, position text, posid integer);");

          db.execSQL("insert into people_tmp select id, name, position, posid from people;");
          db.execSQL("drop table people;");

          db.execSQL("create table people ("
              + "id integer primary key autoincrement,"
              + "name text, posid integer);");

          db.execSQL("insert into people select id, name, posid from people_tmp;");
          db.execSQL("drop table people_tmp;");

          db.setTransactionSuccessful();
        } finally {
          db.endTransaction();
        }
      }
    }

  }
}

Ders Sonu Notları:

Bugünkü dersimizde onUpgrade metodu kullanarak veri tabanın versiyonu güncellemeyi öğrendik. Gelecek derslerde pratik örnekleri kullanarak sqlite ait komutları inceleyeceğiz.