Как исправить ошибку «каждая переменная связывания в запросе должна иметь соответствующий параметр метода» в Android Java? - PullRequest
2 голосов
/ 29 сентября 2019

Я попытался реализовать простую RoomDB в приложении для Android, в котором есть только 1 таблица и объекты Task в ней, предварительно загруженные с помощью обратного вызова databaseBuilder.Когда я пытаюсь построить приложение, я получаю, что каждая переменная связывания в запросе должна иметь ошибку соответствующего параметра метода, но если я нажму кнопку «Выполнить» во второй раз, она компилирует приложение, но я не могу ничего вставить в базу данных, и еслиЯ пытаюсь запросить предварительно загруженную задачу по ее идентификатору (0), который возвращает null.

Это мой класс задач, который я хочу сохранить в БД:

@Entity(tableName = "tasks")
public class Task {

    @PrimaryKey(autoGenerate = true)
    private int taskId;
    @ColumnInfo(name = "Description")
    private String description;

    public Task(String description) {
        this.description = description;
    }

    public void setTaskId(int taskId) {
        this.taskId = taskId;
    }


    public int getTaskId() {
        return taskId;
    }

    public String getDescription() {
        return description;
    }

    @NonNull
    @Override
    public String toString() {
        return "Task object, id: "+taskId;
    }
}

И этомой TaskDAO:

@Dao
public interface TaskDAO {

    @Query("SELECT * FROM tasks")
    List<Task> getAll();

    @Query("SELECT * FROM tasks WHERE taskId = (:taskId)")
    Task getTaskById(int taskId);

    @Insert
    void insertAll(Task...tasks);

}

И это класс базы данных:

@Database(entities = {Task.class}, version = 1)
public abstract class AppDatabase extends RoomDatabase {
    private static AppDatabase INSTANCE;

    public abstract TaskDAO taskDAO();

    public static AppDatabase getAppDatabase(Context context) {
        if (INSTANCE == null) {
            INSTANCE = Room.databaseBuilder(context.getApplicationContext(), AppDatabase.class, "tasks.db")
                    .addCallback(new Callback() {
                        @Override
                        public void onCreate(@NonNull SupportSQLiteDatabase db) {
                            super.onCreate(db);
                            new PopulateInitialData(INSTANCE).execute();
                        }
                    }).build();
        }
        return INSTANCE;
    }

    private static class PopulateInitialData extends AsyncTask<Void, Void, Void> {

        private final TaskDAO taskDAO;

        public PopulateInitialData(AppDatabase database){
            taskDAO = database.taskDAO();
        }

        @Override
        protected Void doInBackground(Void... voids) {
            Task task1 = new Task("Task data");

            taskDAO.insertAll(new Task[] {task1});
            return null;
        }
    }
}

И вот как я вызываю БД и пытаюсь запросить задачу:

AppDatabase roomDB = AppDatabase.getAppDatabase(getApplicationContext());
new Thread(new Runnable() {
    @Override
    public void run() {
        Task task = roomDB.taskDAO().getTaskById(0)); //task is null
    }
}).start();

1 Ответ

2 голосов
/ 29 сентября 2019

Метод insertAll ожидает, что массив объектов Task (Task[]) не является единственным объектом Task.

Если вы хотите вставить один объект Task, вы можете добавить новыйметод вставки в DAO, например:

@Insert
void insertOneTask(Task task);

Альтернативно используйте массив из одного элемента с текущим методом insertAll .

например,

taskDAO.insertAll(new Task[]{task1});

, но я не могу ничего вставить в базу данных, и если я пытаюсь запросить предварительно загруженную задачу по ее идентификатору (0), она возвращает ноль.

Это потому, что при нормальных обстоятельствах никогда не будет задачи с идентификатором 0. Первый идентификатор будет 1.

Если вы использовали следующий код

            List<Task> alltasks = roomDB.taskDAO().getAll();
            for (Task t: alltasks) {
                Log.d("TASKINFO","Task =" + t.getDescription() + " ID = " + t.getTaskId());
            }

после / до или вместо Task task = roomDB.taskDAO().getTaskById(0)); //task is null

Будет показано, что идентификатор задачи равен 1.

например, 2019-09-29 20:00:20.463 D/TASKINFO: Task =Task data ID = 1

Комуобъяснение ROOM создаст таблицу для Задач, используя: -

CREATE TABLE IF NOT EXISTS `tasks` (`taskId` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `Description` TEXT)

Столбец taskid, будет псевдонимом столбца rowid и, если не указано значение, или предоставленное значение равно нулю.Затем он автоматически сгенерирует значение для rowid и, следовательно, его псевдоним.Значение будет на 1 больше, чем наибольшее из последних записанных значений или самое высокое значение, которое в настоящее время находится в базе данных.Если таких значений нет, то значение будет 1 .

Если вы использовали

Task task = roomDB.taskDAO().getTaskById(1));

Вставленная задача будет возвращена.

Как правило, вы никогда не должны делать предположений о значении идентификатора, скорее его следует получать программно, обычно из списка, но с ROOM вы обычно имеете дело с объектами (например, getAll () и последующим циклом for).как указано выше)

Тестирование

Код был протестирован с использованием следующего: -

  • Task.java Скопирован Asis и без изменений
  • TaskDAO.java скопировал asis и без изменений.
  • AppDatabase.java скопировал asis и без изменений.

  • И вот как я вызываю БД и пытаюсь запросить задачу:

    • Удалил этот код в MainActivity.java

    • Сделал roomDB переменной класса (AppDatabase roomDB), просто создав ее экземпляр в методе onCreate.

    • Также исправлена ​​ошибка (лишние скобки) и

    • Добавлен код getAll и цикл сверху.

согласно: -

public class MainActivity extends AppCompatActivity {

    AppDatabase roomDB;

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

        roomDB = AppDatabase.getAppDatabase(getApplicationContext());
        new Thread(new Runnable() {
            @Override
            public void run() {
                Task task = roomDB.taskDAO().getTaskById(0); //task is null
                List<Task> alltasks = roomDB.taskDAO().getAll();
                for (Task t: alltasks) {
                    Log.d("TASKINFO","Task =" + t.getDescription() + " ID = " + t.getTaskId());
                }
            }
        }).start();
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...