Обновите запись, если она существует, иначе вставьте новую запись в комнату.

Я новичок в Room, Rxjava и других компонентах архитектуры Android. Я пытаюсь обновить/вставить 2 записи (если строка уже существует, обновите ее. В противном случае вставьте новую строку). Я пытался сделать это следующим образом. Но я не работал.

Игровая активность:

public class GameActivity extends AppCompatActivity {

...

    public void onGameWinnerChanged(Player winner) {


    mDisposable.add(gameViewModel.updateDb(winner)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
            .subscribe(() -> Log.e("Success!!!", "updated records")
                    , throwable -> {
                throwable.printStackTrace();
            }));        
      }
}

Модель GameView:

public class GameViewModel extends ViewModel {

    ...

    public Completable updateDb(Player winner) {

        return Completable.fromAction(() -> {
            updateWinner(winner);
            Player loser = game.player1 == winner ? game.player2 : game.player1;
            updateLoser(loser);
        });
    }

    private void updateLoser(Player loser) {

           User user = userDataSource.getSingleRecordFromName(loser.name);
        if (user != null) {
            user.loss++;
            userDataSource.updateRecord(user);
        } else {
            user = new User(loser.name, "", 0, 0, 1);
            userDataSource.insertOrUpdateUser(user);
        }
    }

    private void updateWinner(Player winner) {

      User user = userDataSource.getSingleRecordFromName(winner.name);
      if (user != null) {
            user.wins++;
            userDataSource.updateRecord(user);
      } else {
            user = new User(winner.name, "", 0, 1, 0);
            userDataSource.insertOrUpdateUser(user);
      }
   }
}

Источник данных пользователя

public class LocalUserDataSource implements UserDataSource {

    private DaoAccess daoAccess;

    public LocalUserDataSource(DaoAccess daoAccess){
        this.daoAccess=daoAccess;
    }

    @Override
    public Flowable<List<User>> getUsers() {
        return daoAccess.fetchAllData();
    }

    @Override
    public void insertOrUpdateUser(User user) {
        Log.e("local user ds","insertOrUpdateUser");
        daoAccess.insertOnlySingleRecord(user);
    }

    @Override
    public User getSingleRecordFromName(String strName) {
        return daoAccess.getSingleRecord(strName);
    }


    @Override
    public void updateRecord(User user) {
        daoAccess.updateRecord(user);
    }

    @Override
    public void deleteRecord(User user) {
        daoAccess.deleteRecord(user);
    }
}

DaoAccess

@Dao
public interface DaoAccess  {

    @Insert
    void insertOnlySingleRecord(User user);

    @Query("SELECT * FROM User")
    Flowable<List<User>> fetchAllData();

    @Query("SELECT * FROM User WHERE name =:strName")
    User getSingleRecord(String strName);

    @Update
    void updateRecord(User user);

    @Delete
    void deleteRecord(User user);
}

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

User user = userDataSource.getSingleRecordFromName(loser.name);

Может ли кто-нибудь сказать мне, где я не прав или что мне делать?

Изменить

Что я хочу сделать, так это сначала получить пользователя, если он есть в базе данных, обновить, увеличить или уменьшить счет (если победитель, то +1 к столбцу побед, если проигравший, то +1 к столбцу проигрыша). Если пользователь не существует в таблице, создайте новую запись.


person Riddhi    schedule 14.04.2018    source источник
comment
@Insert(onConflict = OnConflictStrategy.REPLACE) void insertOnlySingleRecord(User user); можно обновить или заменить вот так. в вашем `DaoAccess`   -  person KuLdip PaTel    schedule 14.04.2018
comment
@KuLdipPaTel Пожалуйста, смотрите отредактированный вопрос   -  person Riddhi    schedule 14.04.2018
comment
@KuLdipPaTel, тогда каким должен быть запрос для получения одной записи в этом случае?   -  person Riddhi    schedule 14.04.2018
comment
во-первых, вы должны предотвратить вставку повторяющейся записи, во-вторых, если ваше имя игрока содержит пробел, который вы должны изменить в своем getSingleRecord запросе.   -  person KuLdip PaTel    schedule 14.04.2018
comment
Вы можете объяснить больше? как я этого добьюсь? @КуЛдипПаТел   -  person Riddhi    schedule 14.04.2018
comment
@Riddhi Как ты это решил?   -  person Francis    schedule 06.11.2018


Ответы (2)


ваш пользовательский Dao должен быть таким, как показано ниже

@Dao
public interface DaoAccess  {

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    void insertOnlySingleRecord(User user);

    @Query("SELECT * FROM User")
    Flowable<List<User>> fetchAllData();

    @Query("SELECT * FROM User WHERE lower(name) = lower(:strName) limit 1")
    User getSingleRecord(String strName);

    @Update
    void updateRecord(User user);

    @Delete
    void deleteRecord(User user);
}

ваш объект пользователя должен выглядеть как

 @Entity(tableName = "user_table", indices = @Index(value = {"name"}, unique = true))
public class UserEntity {

    @PrimaryKey(autoGenerate = true)
    private int id;

    @ColumnInfo(name = "name")
    private String name;
 }
person KuLdip PaTel    schedule 14.04.2018
comment
благодарю вас. Я сделаю это. Но, мой вопрос отличается в этом случае. Я хочу сначала получить пользователя, если он есть в базе данных, обновить, увеличить или уменьшить счет (если победитель, то +1 к столбцу побед, если проигравший, то +1 к столбцу проигрыша). Если пользователь не существует в таблице, создайте новую запись. - person Riddhi; 14.04.2018
comment
вот, indices = @Index(value = {"name"} что это значит? - person Riddhi; 14.04.2018
comment
он вставит уникальное имя пользователя, если оно конфликтует, оно заменит или обновит предыдущую запись. - person KuLdip PaTel; 14.04.2018
comment
В порядке. Спасибо еще раз. - person Riddhi; 14.04.2018
comment
поэтому вам не нужно проверять, что пользователь уже существует или нет. просто вставьте запись - person KuLdip PaTel; 14.04.2018
comment
В порядке. Получил вашу точку зрения. Но в моем случае я хотел также обновить еще одно поле (победы/проигрыши) (своего рода увеличение количества очков). тогда, не извлекая пользователя из таблицы, как я узнаю текущий счет и увеличиваю его. - person Riddhi; 14.04.2018
comment
Проверьте это здесь: developer.android.com/training /data-storage/room/ Очень четко! - person Bulma; 19.05.2020

Вы можете просто проверить, существуют ли данные в БД, используя этот запрос

// It will return **TRUE** if user exist in User Table else return **FALSE** 

@Query("SELECT * FROM User WHERE name == :strName")
    fun isUserExist(strName: String): Boolean

// It will return **user count** if user exist in User Table else return **0**

@Query("SELECT * FROM User WHERE name == :strName")
    fun isUserExist(strName: String): Int

// It will return **User** if user exist in User Table else return **null**

@Query("SELECT * FROM User WHERE name == :strName")
    fun isUserExist(strName: String): User
person Rahul Rathore    schedule 01.10.2020