Понимание транзакций в Firebase - PullRequest
0 голосов
/ 06 ноября 2019

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

Моя БД структурирована следующим образом:

{
  "config" : {
    "20191108" : { // each date has a different amount of shifts under it
      "-Lt53nxPc9_lBy7EvRQa" : { // generated key for shift
        "endTime" : "00:00",
        "name" : "morning",
        "numOfEmps" : 2,
        "startTime" : "00:00",
        "users" : {
          "12345" : true,
          "54321" : true
        },
        "wage" : 0
      }
    }
  },
  "users" : {
    "12345" : {
        id: "12345",
        password : "aaaaa"
    },
    "33333" : {
        id: "33333",
        password : "bbbbb"
    },
    "54321" : {
        id: "54321",
        password : "c3c3c3"
    }
  }
}

Цель состоит в том, чтобы позволить пользователям добавлять себя в смену (ы) по своему выбору (в соответствии с ограничениями).

У каждой смены есть отдельное поле numOfEmps, которое указывает, сколько пользователей может быть назначено для этой конкретной смены.

Я определил две модели в своем приложении - User и Shift.

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

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

Мой код:

 add.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            //Constraint No. 0
            //chosen date < today's date, user cannot assign themselves to prior shifts
            String today = DateTimeFormatter.BASIC_ISO_DATE.format(LocalDate.now());
            if(today.compareTo(dates[0]) >= 0){
                Toast.makeText(context, "Cannot assign to prior shifts", Toast.LENGTH_SHORT).show();
                return;
            }

            DatabaseReference mDatabase = FirebaseDatabase.getInstance().getReference();
            mDatabase.child("config").child(dates[0]).child(shift.getKey()).child("users").runTransaction(new Transaction.Handler() {
                @Override
                public Transaction.Result doTransaction(MutableData mutableData) {

                    if(mutableData == null){
                        // Set value and report transaction success
                        mutableData.child(user.getId()).setValue(true);

                        return Transaction.success(mutableData);
                    }
                    // here I'd like to check if the user is already assigned
                    // or if numOfEmps is equal to number of children under "users" node
                    // and if so, abort transaction
                    return Transaction.success(mutableData);
                }

                @Override
                public void onComplete(DatabaseError databaseError, boolean b,
                                       DataSnapshot dataSnapshot) {
                    if(b){
                        // update Expandable List View
                        List<User> usersList = collection.get(shift);
                        usersList.add(user);
                        notifyDataSetChanged();
                    }else{
                        Toast.makeText(context, "User already assigned to shift", Toast.LENGTH_SHORT).show();
                    }
                }
            });
        }
    });

Документация Firebaseвыполняет транзакцию для одного объекта (целое число).

Я хочу расширить его для обработки списка объектов (Пользователи).

Буду признателен за помощь в решении этой проблемы. Спасибо.

1 Ответ

0 голосов
/ 06 ноября 2019

Прямо сейчас вы устанавливаете здесь все изменяемые данные:

mutableData.setValue(user);

Таким образом, вы перезаписываете все, что находится под /users значением user.

ВыВам нужно будет установить данные только для конкретного пользователя, что вы можете сделать с помощью:

mutableData.child(user.getKey()).setValue(user);

Несколько дополнительных замечаний о вашем подходе:

  • Поскольку вывы нигде не используете DataSnapshot из shiftRef.addListenerForSingleValueEvent(, поэтому я бы порекомендовал удалить этого слушателя. В целом: размещение транзакции внутри обычного прослушивателя - это серьезный запах кода, поскольку предполагается, что ваша транзакция зависит только от данных, которые вы читаете в самой транзакции (в противном случае: зачем вам сначала использовать транзакцию).
  • Если вы хотите создать push-идентификатор внутри транзакции, вы можете просто позвонить shiftRef.push().getKey(). Это чисто клиентская операция.
  • Выполнение транзакции в списке обычно приводит к проблемам с производительностью / конфликтам при добавлении в список большего количества пользователей. Рассмотрите возможность использования модели данных, у которой нет этой проблемы.
  • Например: вам лучше хранить пользователей под их ID. Таким образом, вы можете напрямую искать пользователя, вместо того, чтобы читать все из них и искать на стороне клиента (что не будет масштабироваться, если у вас будет много пользователей). Таким образом, в этом случае ваша транзакция может выполняться на /users/$uid.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...