Как эффективно управлять операциями CRUD из основного SQLiteOpenHelper – android studio

Я не согласен с тем, как я хочу построить свою архитектуру базы данных. Прежде всего, я использую одноэлементный шаблон для базы данных, чтобы застраховать один ее экземпляр (чтобы он был потокобезопасным), а также чтобы получить работоспособную ссылку на базу данных, где бы у меня ни был контекст.

Во всем приложении я выполняю много разных операций с базами данных, например, для некоторых действий нужно изменить только таблицу «Meals», а для некоторых нужно изменить, например, «Meals» и «MealFoods».

Для каждой из этих таблиц я создал вспомогательный класс, чтобы отделить операции CRUD каждой таблицы от класса DatabaseManager (который расширяет SQLiteOpenHelper). Это, конечно, сделано для простоты и более чистого кода.

Первый подход:

Этот подход сохраняет все вспомогательные классы внутри DatabaseManager.

DatabaseManager.java:

public class DatabaseManager extends SQLiteOpenHelper {
    private static String dbName = "logs.db";
    private static final int dbVersion = 1;

    private final Context context;
    public MealsDBHelper mealsDBHelper;
    public MealFoodsDBHelper mealFoodsDBHelper;

    private DatabaseManager(@NonNull Context context) {
        super(context, dbName, null, dbVersio);
        this.context = context.getApplicationContext();//Saving as application context to avoid leaks
        mealsDBHelper = new MealsDBHelper(context);
        mealFoodsDBHelper = new MealFoodsDBHelper(context);
    }

    private static DatabaseManager instance;
    public static synchronized DatabaseManager getInstance(Context context) {
        if (instance == null) {
            instance = new DatabaseManager(context);
        }
        return instance;
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        //...
    }

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

Давайте посмотрим на класс MealsDBHelper, который почти все, что он делает, – это помогает передавать операции CRUD с базой данных. (Например, пользователь хочет изменить название своей еды)

public class MealsDBHelper {
    public static final String MEALS_TABLE_NAME = "Meals";
    public static final String MEAL_ID_COLUMN = "Meal_ID";
    public static final String MEAL_NAME_COLUMN = "Meal_Name";
    public static final String MEAL_POS_COLUMN = "Meal_Pos";
    public static final String MEAL_DATE_COLUMN = "Date";


    private Context context; //A context object to pass on to the DatabaseManager.getInstance method in all the different methods inside this class
    public MealsDBHelper(Context context){
        this.context = context;
    }

    //For example one of few methods that do operations on the 'Meals' table in the database.
    public void updateMealName(long mealId, String meal_name) {
        UserDataDB.getInstance(context).getWritableDatabase().execSQL("UPDATE " + MEALS_TABLE_NAME + " SET " + MEAL_NAME_COLUMN + " = '" + meal_name + "' WHERE " + MEAL_ID_COLUMN + " = " + mealId);
    }
}

Теперь, независимо от того, изменяет ли действие 1, 2 или даже 3 таблицы, я могу обновить название блюда следующим образом:

DatabaseManager.getInstance(context).mealsDBHelper.updateMealName(mealId, mealName);

Это потому, что DatabaseManager содержит ссылку на все другие вспомогательные классы.

Что мне нравится в этом подходе, так это то, что я могу просто получить доступ к каждой таблице и выполнять с ней операции в соответствии со своими потребностями, и что мне не нравится, так это то, что класс DatabaseManager содержит ссылку для всех помощников, и я не уверен, что лучше так сделать ..

Второй подход:

Этот подход не сохраняет все вспомогательные классы внутри DatabaseManager.

DatabaseManager.java:

public class DatabaseManager extends SQLiteOpenHelper {
    private static String dbName = "logs.db";
    private static final int dbVersion = 1;

    private final Context context;

    private DatabaseManager(@NonNull Context context) {
        super(context, dbName, null, dbVersio);
        this.context = context.getApplicationContext();//Saving as application context to avoid leaks
    }

    private static DatabaseManager instance;
    public static synchronized DatabaseManager getInstance(Context context) {
        if (instance == null) {
            instance = new DatabaseManager(context);
        }
        return instance;
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        //...
    }

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

Теперь, если в моей деятельности необходимо изменить таблицы Meals и MealFoods, я могу создать в onCreate помощников, например:

public class AddFoodActivity extends AppCompatActivity{

    MealsDBHelper mealsDBHelper;
    MealFoodsDBHelper mealFoodsDBHelper;

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

        mealsDBHelper = new MealsDBHelper(this);
        mealFoodsDBHelper = new MealFoodsDBHelper(this);
    }

    //Then whenever I need to modify the table I use:
    mealsDBHelper.updateMealName(mealId, mealName);
}

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

В принципе, есть ли недостатки у использования одного из методов?

Признаюсь, в этом посте я оставил большой кусок кода, но это только потому, что я думаю, что это не сильно повлияет на ваше понимание проблемы, потому что это более общая проблема.

Большое спасибо за любую помощь.

0

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *