Я использую базу данных комнат в Android Studio, и, похоже, я не могу правильно обновить поле элемента в базе данных

#android #database #android-studio #android-room

Вопрос:

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

Я использую базу данных комнат, как указано, вот мои классы, связанные с базой данных:

 @Entity(tableName="board")
public class BoardItem {

    @PrimaryKey(autoGenerate = true)
    @ColumnInfo(name="board_id")
    private int boardId;
    @ColumnInfo(name="board_name")
    private String boardName;
    @ColumnInfo(name="board_description")
    private String boardDescription;
    @ColumnInfo(name="board_image_list")
    @TypeConverters(ImageListTypeConverter.class)
    private List<ImageItem> boardImageList;

    public BoardItem(String boardName, String boardDescription){
        this.boardName = boardName;
        this.boardDescription = boardDescription;
        this.boardImageList = new ArrayList<>();
    }

    public int getBoardId() { return boardId; }

    public String getBoardName() {
        return boardName;
    }

    public String getBoardDescription() {
        return boardDescription;
    }

    public String getPhotosCount() {
        return String.valueOf(this.boardImageList.size());
    }
    public void setBoardId(int boardId) {
        this.boardId = boardId;
    }

    public List<ImageItem> getBoardImageList() {
        return boardImageList;
    }

    public void setBoardImageList(List<ImageItem> list) { this.boardImageList = list; }
 
 @Dao
public interface BoardItemDAO {

    @Insert(onConflict = OnConflictStrategy.IGNORE)
    void addBoardItem(BoardItem boardItem);

    @Transaction
    @Query("SELECT * from board ORDER BY board_id DESC")
    LiveData<List<BoardItem>> getBoardItems();

    @Transaction
    @Query("SELECT * from board ORDER BY board_id DESC")
    List<BoardItem> getBoardItemsNow();

}
 
 @Database(entities =  {BoardItem.class}, version = 1)
public abstract class BoardItemDatabase  extends RoomDatabase {

    public abstract BoardItemDAO boardItemDAO();

    //Singleton
    private static volatile BoardItemDatabase INSTANCE;
    private static final int NUMBER_OF_THREADS = 4;
    static final ExecutorService databaseWriteExecutor = Executors.newFixedThreadPool(NUMBER_OF_THREADS);

    static BoardItemDatabase getDatabase(final Context context){

        if (INSTANCE == null) {
            synchronized (BoardItemDatabase.class) {
                if (INSTANCE == null) {
                    INSTANCE = Room.databaseBuilder(context.getApplicationContext(), BoardItemDatabase.class, "board_database")
                            .allowMainThreadQueries()
                            .build();
                }
            }
        }

        return INSTANCE;
    }

}
 
 //Repository

public class BoardItemRepository {

    private BoardItemDAO boardItemDAO;
    private LiveData<List<BoardItem>> boardItemList;
    private List<BoardItem> boardItemListNow;

    public BoardItemRepository (Application application) {
        BoardItemDatabase db = BoardItemDatabase.getDatabase(application);
        boardItemDAO = db.boardItemDAO();
        boardItemList = boardItemDAO.getBoardItems();
        boardItemListNow = boardItemDAO.getBoardItemsNow();
    }

    //Room executes all queries on a separate thread
    //Observed LiveData will notify the observer when data has changed
    public LiveData<List<BoardItem>> getBoardItemList() { return boardItemList; }

    //this method is called on a non-UI thread or the app will throw an exception. Room ensures
    //that there are no long running operations on the main thread, blocking the UI.
    public void addBoardItem(final BoardItem boardItem) {
        BoardItemDatabase.databaseWriteExecutor.execute(() -> boardItemDAO.addBoardItem(boardItem));
    }

    public List<BoardItem> getBoardItemListNow() {return boardItemListNow; }

}
 

Note that BoardItem and ImageItem are classes I made myself: a board is supposed to contain multiple ImageItems.

My boardItem has different fields, one of which is a list of ImageItems.
Now, in a specific fragment I try to update this list of ImageItems in a board that already exists in my database, which is the board with id = 0 (the very first board in the db). I try to retrieve the list from the Database and replace it with a new one.

I have used LiveData in certain cases to update the view of my app when the item change, but I have non LiveData methods for this specific piece of my code I need to change my database as soon as I click the button that contains this code:

 List<BoardItem> boardItems = boardListViewModel.getBoardItemsNow();

newList = boardItems.get(0).getBoardImageList();
newList.add(newItem);
boardItems.get(0).setBoardImageList(newList);

 

Когда я нажимаю кнопку, код выполняется без ошибок, но база данных не обновляется; она содержит список, как и раньше, без нового элемента.

Заранее спасибо, еще раз извините, если это звучит запутанно!

РЕДАКТИРОВАТЬ: вот моя модель просмотра:

 public class BoardListViewModel extends AndroidViewModel {

    private final MutableLiveData<BoardItem> boardSelected = new MutableLiveData<>();
    private LiveData<List<BoardItem>> boardItems;
    private List<BoardItem> boardItemsNow;

    public BoardListViewModel(@NonNull Application application) {
        super(application);
        BoardItemRepository repo = new BoardItemRepository(application);
        boardItems = repo.getBoardItemList();
        boardItemsNow = repo.getBoardItemListNow();
    }

    public void select(BoardItem boardItem) {
        boardSelected.setValue(boardItem);
    }

    public LiveData<BoardItem> getSelected() {
        return boardSelected;
    }

    public LiveData<List<BoardItem>> getBoardItems() {
        return boardItems;
    }

    public BoardItem getBoardItem(int position) {
        return boardItems.getValue() == null ? null : boardItems.getValue().get(position);
    }

    public List<BoardItem> getBoardItemsNow() { return boardItemsNow; }
}

 

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

1. как вы используете живые данные?

2. @iamanbansal Я использую живые данные в другом фрагменте. У меня есть представление рециркулятора, и каждый раз, когда данные меняются, я обновляю представление рециркулятора: boardListViewModel = new ViewModelProvider((ViewModelStoreOwner)activity) .get(BoardListViewModel.class); boardListViewModel.getBoardItems().observe((LifecycleOwner) activity, boardItems -> adapter.setData(boardItems));

3. что делает setData функция?

4. Использовать метод вставки для сохранения данных?

5. Можете ли вы показать свои view model ?

Ответ №1:

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

 @Insert(onConflict = OnConflictStrategy.IGNORE)
void addBoardItem(BoardItem boardItem);
 

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

Что вам следует сделать, так это обновить существующую строку, поэтому вам нужен dao @Update.

Поэтому добавьте, а затем используйте следующий dao :-

 @Update(onConflict = OnConflictStrategy.IGNORE)
int updateBoardItem(BoardItem boardItem);
 
  • int возвращаемое значение-это количество строк, которые были обновлены (вы ожидали бы 1, 0, если бы конфликт привел к игнорированию обновления).

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

1. Я думаю, что я бы реализовал метод updateBoardItem в своем репозитории, написав что-то вроде BoardItemDatabase.databaseWriteExecutor.execute(() -> boardItemDAO.updateBoardItem(boardItem)); . Однако я не уверен, как я должен проверить, правильно ли обновлен элемент, и, следовательно, вернуть правильный int.

2. Я применил ваше предложение, и теперь оно отлично работает! Я не думал, что это будет так же просто, как сделать запрос на обновление.