Должен ли я создать класс, который наследует SQLiteOpenHelper для каждой таблицы в моей базе данных?

#android #sqlite #android-sqlite #android-database

#Android #sqlite #android-sqlite #android-база данных

Вопрос:

Мне нужно создать базу данных приложения Android, но мне было интересно, должен ли я создать один класс, который наследует SQLiteOpenHelper для каждой таблицы, существующей в моей базе данных? Или я должен создать один класс: например, MyAppDatabase, который наследует от SQLiteOpenHelper и создает все мои таблицы в методе onCreate, а также функции обновления и удаления?

Какие-либо рекомендации?

Комментарии:

1. Конечно, по 1 классу на базу данных, а не на таблицу.

Ответ №1:

Вам нужен только один помощник базы данных для всех таблиц в базе данных, и, таким образом, вы бы использовали один метод onCreate для создания таблиц. Обратите внимание, что если бы у вас было несколько помощников базы данных, то onCreate (и метод onUpdate) вызывался бы только один раз первым помощником, который открыл базу данных, и, таким образом, в дополнение к неэффективности нескольких помощников, могло бы быть сложнее иметь несколько помощников базы данных.

Более конкретно, onCreate вызывается автоматически только тогда, когда база данных не существует. К моменту вызова onCreate сама база данных была создана.

onUpdate вызывается только тогда, когда при открытии базы данных номер версии, переданный вызову (через суперзвонок), больше номера версии, хранящегося в файле базы данных. Номер версии, сохраненный в файле на данный момент, затем обновляется, чтобы отразить более новую версию. Следовательно, последующие вызовы не будут вызывать метод onUpgrade.

Независимо от того, разделяете ли вы методы и идентификаторы, такие как имена столбцов / таблиц для отдельных таблиц, это выбор, который вы могли бы сделать. Некоторые могут посчитать неудобным разделение, другие могут подумать, что так понятнее.

Пример

Следующий код является примером 3 перестановок (а также баз данных), которые используют 2 таблицы, а именно table001 (столбцы _id и mydata) и table001 (имена столбцов _id и myotherdata).

  1. использует один DatabaseHelper (DBHelper001) со всем, что встроено в помощник. База данных — mydb001

  2. использует один databasehelper (DBHelper002) с табличными методами и константами в конкретных таблично-ориентированных классах (класс Table001 и класс Table002).

  3. использует два отдельных помощника базы данных (DBHelperTable001 и DBHelperTable002) и для простоты кода использует классы Table001 и Table002.

    • Обратите внимание, что для преодоления того, что onCreate вызывается только один раз, метод onOpen также пытается создать соответствующую таблицу ( CREATE TABLE IF NOT EXISTS ...... что важно в данном случае для предотвращения сбоя, когда таблица действительно существует).
    • Обратите внимание, что это всего лишь один недостаток наличия нескольких помощников.

Сначала классы, специфичные для таблицы (не используемые при первой перестановке)

Table001.java

 public class Table001 {

    public static final String TBL_TABLE001 = "table001";
    public static final String COL_TABLE001_ID = BaseColumns._ID;
    public static final String COL_TABLE001_MYDATA = "mydata";

    public static String getCrtSQL() {
        return "CREATE TABLE IF NOT EXISTS "   TBL_TABLE001   "("  
                COL_TABLE001_ID   " INTEGER PRIMARY KEY, "  
                COL_TABLE001_MYDATA   " TEXT"  
                ")";
    }

    public static long insert(SQLiteDatabase db, String mydata) {
        ContentValues cv = new ContentValues();
        cv.put(COL_TABLE001_MYDATA,mydata);
        return db.insert(TBL_TABLE001,null,cv);
    }

    public static Cursor getAll(SQLiteDatabase db) {
        return db.query(TBL_TABLE001,null,null,null,null,null,null);
    }
}
  

Table002.java

 public class Table002 {

    public static final String TBL_TABLE002 = "table002";
    public static final String COL_TABLE002_ID = BaseColumns._ID;
    public static final String COL_TABLE002_MYOTHERDATA = "myotherdata";

    public static String getCrtSQL() {
        return "CREATE TABLE IF NOT EXISTS "   TBL_TABLE002   "("  
                COL_TABLE002_ID   " INTEGER PRIMARY KEY, "  
                COL_TABLE002_MYOTHERDATA   " TEXT"  
                ")";
    }

    public static long insert(SQLiteDatabase db, String mydata) {
        ContentValues cv = new ContentValues();
        cv.put(COL_TABLE002_MYOTHERDATA,mydata);
        return db.insert(TBL_TABLE002,null,cv);
    }

    public static Cursor getAll(SQLiteDatabase db) {
        return db.query(TBL_TABLE002,null,null,null,null,null,null);
    }
}
  

Четыре вспомогательных класса базы данных

DBHelper001.java — (автономный)

 public class DBHelper001 extends SQLiteOpenHelper {

    public static final String DBNAME = "mydb001";
    public static final int DBVERSION = 1;

    public static final String TBL_TABLE001 = "table001";
    public static final String TBL_TABLE002 = "table002";
    public static final String COL_TABLE001_ID = BaseColumns._ID;
    public static final String COL_TABLE001_MYDATA = "mydata";
    public static final String COL_TABLE002_ID = BaseColumns._ID;
    public static final String COL_TABLE002_MYOTHERDATA = "myotherdata";

    public DBHelper001(Context context) {
        super(context, DBNAME, null, DBVERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        String crt_table001_sql = "CREATE TABLE IF NOT EXISTS "   TBL_TABLE001   "("  
                COL_TABLE001_ID   " INTEGER PRIMARY KEY,"  
                COL_TABLE001_MYDATA   " TEXT"  
                ")";
        String crt_table002_sql = "CREATE TABLE IF NOT EXISTS "   TBL_TABLE002   "("  
                COL_TABLE002_ID   " INTEGER PRIMARY KEY,"  
                COL_TABLE002_MYOTHERDATA   " TEXT"  
                ")";
        db.execSQL(crt_table001_sql);
        db.execSQL(crt_table002_sql);
    }

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

    }

    public long insertIntoTable001(String mydata) {
        SQLiteDatabase db = this.getWritableDatabase();
        ContentValues cv = new ContentValues();
        cv.put(COL_TABLE001_MYDATA,mydata);
        return db.insert(TBL_TABLE001,null,cv);
    }

    public long insertIntoTable002(String myotherdata) {
        SQLiteDatabase db = this.getWritableDatabase();
        ContentValues cv = new ContentValues();
        cv.put(COL_TABLE002_MYOTHERDATA,myotherdata);
        return db.insert(TBL_TABLE002,null,cv);
    }

    public Cursor getAllFromTable001() {
        SQLiteDatabase db = this.getWritableDatabase();
        return db.query(TBL_TABLE001,null,null,null,null,null,null);
    }

    public Cursor getAllFromTable002() {
        SQLiteDatabase db = this.getWritableDatabase();
        return db.query(TBL_TABLE002,null,null,null,null,null,null);
    }
}
  

DBHelper002.java (табличный код в другом месте)

 public class DBHelper002 extends SQLiteOpenHelper {

    public static final String DBNAME = "mydb002";
    public static final int DBVERSION = 1;

    public DBHelper002(Context context) {
        super(context, DBNAME, null, DBVERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(Table001.getCrtSQL());
        db.execSQL(Table002.getCrtSQL());
    }

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

    }
}
  

DBHelperTable001.java (специальный помощник table001)

 public class DBHelperTable001 extends SQLiteOpenHelper {

    public static final String DBNAME = "mydb003";
    public static final int DBVERSION = 1;

    public DBHelperTable001(Context context) {
        super(context, DBNAME, null, DBVERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(Table001.getCrtSQL());
        //NOTE Table002 won't get created as onCreate is only called once
    }

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

    }

    @Override
    public void onOpen(SQLiteDatabase db) {
        super.onOpen(db);
        db.execSQL(Table001.getCrtSQL());
    }
}
  
  • Примечание метод onOpen используется для обхода onCreate, вызываемого только один раз за время существования базы данных.
    • вызов ExecSQL является примером неэффективности этой методологии.

DBHelperTable002.java (помощник для конкретной таблицы 002)

 public class DBHelperTable002 extends SQLiteOpenHelper {

    public static final String DBNAME = "mydb003";
    public static final int DBVERSION = 1;

    public DBHelperTable002(Context context) {
        super(context, DBNAME, null, DBVERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(Table002.getCrtSQL());
        //NOTE Table001 won't get created as onCreate is only called once
    }

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

    }

    @Override
    public void onOpen(SQLiteDatabase db) {
        super.onOpen(db);
        db.execSQL(Table002.getCrtSQL());
    }
}
  

Tying them all together

The following activity utilises (MainActivity.java) utilises all 3 permutations. For each a row is added to each table and then all data from each table is extracted into a cursor which is then dumped (output to the log).

Note that for the table specific helpers each helper is used to extract rows (showing the redundancy aspect).

MainActivity.java

 public class MainActivity extends AppCompatActivity {

    DBHelper001 mDBHlpr1;
    DBHelper002 mDBHlpr2;
    DBHelperTable001 mTblDBHlpr1;
    DBHelperTable002 mTblDBHlpr2;
    Cursor mCsr;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mDBHlpr1 = new DBHelper001(this);
        mDBHlpr1.insertIntoTable001("my data for table001 in mydb001");
        mDBHlpr1.insertIntoTable002("my other data for table002 in mydb001");
        mCsr = mDBHlpr1.getAllFromTable001();
        DatabaseUtils.dumpCursor(mCsr);
        mCsr = mDBHlpr1.getAllFromTable002();
        DatabaseUtils.dumpCursor(mCsr);


        mDBHlpr2 = new DBHelper002(this);
        Table001.insert(mDBHlpr2.getWritableDatabase(),"my data for table001 in mydb002");
        Table002.insert(mDBHlpr2.getWritableDatabase(),"my other data for table002 in mydb002");
        mCsr = Table001.getAll(mDBHlpr2.getWritableDatabase());
        DatabaseUtils.dumpCursor(mCsr);
        mCsr = Table002.getAll(mDBHlpr2.getWritableDatabase());
        DatabaseUtils.dumpCursor(mCsr);

        //Oooops???? wouldn't normally do this
        mCsr = Table001.getAll(mDBHlpr1.getWritableDatabase()); //?????????? from other database!!!
        DatabaseUtils.dumpCursor(mCsr);

        mTblDBHlpr1 = new DBHelperTable001(this);
        Table001.insert(mTblDBHlpr1.getWritableDatabase(),"my data for table001 in mydb003");
        mTblDBHlpr2 = new DBHelperTable002(this);
        Table002.insert(mTblDBHlpr2.getWritableDatabase(),"my data for table002 in mydb003");
        mCsr = Table001.getAll(mTblDBHlpr1.getWritableDatabase());
        DatabaseUtils.dumpCursor(mCsr);
        mCsr = Table002.getAll(mTblDBHlpr1.getWritableDatabase()); //???????????? but OK
        DatabaseUtils.dumpCursor(mCsr);
        mCsr = Table001.getAll(mTblDBHlpr2.getWritableDatabase());
        DatabaseUtils.dumpCursor(mCsr);
        mCsr = Table002.getAll(mTblDBHlpr2.getWritableDatabase()); //??????????? but OK
        DatabaseUtils.dumpCursor(mCsr);
    }
}
  

Результат

Ниже приведен результат первого запуска (обратите внимание, что многократный запуск без удаления приложения приведет к добавлению 2 новых строк) :-

 03-06 11:27:18.453 11093-11093/? I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@12c4306e
03-06 11:27:18.453 11093-11093/? I/System.out: 0 {
03-06 11:27:18.453 11093-11093/? I/System.out:    _id=1
03-06 11:27:18.453 11093-11093/? I/System.out:    mydata=my data for table001 in mydb001
03-06 11:27:18.453 11093-11093/? I/System.out: }
03-06 11:27:18.453 11093-11093/? I/System.out: <<<<<
03-06 11:27:18.453 11093-11093/? I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@275e530f
03-06 11:27:18.453 11093-11093/? I/System.out: 0 {
03-06 11:27:18.453 11093-11093/? I/System.out:    _id=1
03-06 11:27:18.453 11093-11093/? I/System.out:    myotherdata=my other data for table002 in mydb001
03-06 11:27:18.453 11093-11093/? I/System.out: }
03-06 11:27:18.453 11093-11093/? I/System.out: <<<<<


03-06 11:27:18.472 11093-11093/? I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@1006e57a
03-06 11:27:18.472 11093-11093/? I/System.out: 0 {
03-06 11:27:18.472 11093-11093/? I/System.out:    _id=1
03-06 11:27:18.472 11093-11093/? I/System.out:    mydata=my data for table001 in mydb002
03-06 11:27:18.472 11093-11093/? I/System.out: }
03-06 11:27:18.472 11093-11093/? I/System.out: <<<<<
03-06 11:27:18.472 11093-11093/? I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@2337112b
03-06 11:27:18.473 11093-11093/? I/System.out: 0 {
03-06 11:27:18.473 11093-11093/? I/System.out:    _id=1
03-06 11:27:18.473 11093-11093/? I/System.out:    myotherdata=my other data for table002 in mydb002
03-06 11:27:18.473 11093-11093/? I/System.out: }
03-06 11:27:18.473 11093-11093/? I/System.out: <<<<<


03-06 11:27:18.473 11093-11093/? I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@37ef9988
03-06 11:27:18.473 11093-11093/? I/System.out: 0 {
03-06 11:27:18.473 11093-11093/? I/System.out:    _id=1
03-06 11:27:18.473 11093-11093/? I/System.out:    mydata=my data for table001 in mydb001
03-06 11:27:18.473 11093-11093/? I/System.out: }
03-06 11:27:18.473 11093-11093/? I/System.out: <<<<<


03-06 11:27:18.499 11093-11093/? I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@2b786c5d
03-06 11:27:18.500 11093-11093/? I/System.out: 0 {
03-06 11:27:18.500 11093-11093/? I/System.out:    _id=1
03-06 11:27:18.500 11093-11093/? I/System.out:    mydata=my data for table001 in mydb003
03-06 11:27:18.500 11093-11093/? I/System.out: }
03-06 11:27:18.500 11093-11093/? I/System.out: <<<<<
03-06 11:27:18.500 11093-11093/? I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@2038a9d2
03-06 11:27:18.500 11093-11093/? I/System.out: 0 {
03-06 11:27:18.501 11093-11093/? I/System.out:    _id=1
03-06 11:27:18.501 11093-11093/? I/System.out:    myotherdata=my data for table002 in mydb003
03-06 11:27:18.501 11093-11093/? I/System.out: }
03-06 11:27:18.501 11093-11093/? I/System.out: <<<<<
03-06 11:27:18.501 11093-11093/? I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@264a7aa3
03-06 11:27:18.501 11093-11093/? I/System.out: 0 {
03-06 11:27:18.501 11093-11093/? I/System.out:    _id=1
03-06 11:27:18.501 11093-11093/? I/System.out:    mydata=my data for table001 in mydb003
03-06 11:27:18.501 11093-11093/? I/System.out: }
03-06 11:27:18.502 11093-11093/? I/System.out: <<<<<
03-06 11:27:18.502 11093-11093/? I/System.out: >>>>> Dumping cursor android.database.sqlite.SQLiteCursor@3c2611a0
03-06 11:27:18.502 11093-11093/? I/System.out: 0 {
03-06 11:27:18.502 11093-11093/? I/System.out:    _id=1
03-06 11:27:18.502 11093-11093/? I/System.out:    myotherdata=my data for table002 in mydb003
03-06 11:27:18.503 11093-11093/? I/System.out: }
03-06 11:27:18.503 11093-11093/? I/System.out: <<<<<