Zapisz dane

Zanim zaczniesz

Zanim będziesz mógł korzystać z Bazy danych czasu rzeczywistego , musisz:

  • Zarejestruj swój projekt Unity i skonfiguruj go do korzystania z Firebase.

    • Jeśli Twój projekt Unity korzysta już z Firebase, oznacza to, że jest już zarejestrowany i skonfigurowany dla Firebase.

    • Jeśli nie masz projektu Unity, możesz pobrać przykładową aplikację .

  • Dodaj pakiet SDK Firebase Unity (w szczególności FirebaseDatabase.unitypackage ) do swojego projektu Unity.

Pamiętaj, że dodanie Firebase do projektu Unity obejmuje zadania zarówno w konsoli Firebase , jak i w otwartym projekcie Unity (na przykład pobierasz pliki konfiguracyjne Firebase z konsoli, a następnie przenosisz je do projektu Unity).

Zapisywanie danych

Istnieje pięć metod zapisywania danych w bazie danych Firebase Realtime Database:

metoda Typowe zastosowania
SetValueAsync() Zapisz lub zamień dane w zdefiniowanej ścieżce, takiej jak users/<user-id>/<username> .
SetRawJsonValueAsync() Zapisz lub zamień dane na surowy kod Json, taki jak users/<user-id>/<username> .
Push() Dodaj do listy danych. Za każdym razem, gdy wywołujesz Push() , Firebase generuje unikalny klucz, którego można również użyć jako unikalnego identyfikatora, takiego jak user-scores/<user-id>/<unique-score-id> .
UpdateChildrenAsync() Zaktualizuj niektóre klucze dla określonej ścieżki bez zastępowania wszystkich danych.
RunTransaction() Aktualizuj złożone dane, które mogą zostać uszkodzone przez równoczesne aktualizacje.

Uzyskaj odniesienie do bazy danych

Aby zapisać dane w bazie danych, potrzebujesz instancji DatabaseReference :

using Firebase;
using Firebase.Database;

public class MyScript: MonoBehaviour {
  void Start() {
    // Get the root reference location of the database.
    DatabaseReference reference = FirebaseDatabase.DefaultInstance.RootReference;
  }
}

Zapisuj, aktualizuj lub usuwaj dane w odniesieniu

Podstawowe operacje zapisu

W przypadku podstawowych operacji zapisu można użyć SetValueAsync() w celu zapisania danych w określonym odwołaniu, zastępując wszelkie istniejące dane w tej ścieżce. Możesz użyć tej metody do przekazywania typów odpowiadających dostępnym typom JSON w następujący sposób:

  • string
  • long
  • double
  • bool
  • Dictionary<string, Object>
  • List<Object>

Jeśli używasz obiektu C# z typem, możesz użyć wbudowanej funkcji JsonUtility.ToJson() , aby przekonwertować obiekt na surowy obiekt Json i wywołać SetRawJsonValueAsync() . Na przykład możesz mieć klasę User, która wygląda następująco:

public class User {
    public string username;
    public string email;

    public User() {
    }

    public User(string username, string email) {
        this.username = username;
        this.email = email;
    }
}

Możesz dodać użytkownika za pomocą SetRawJsonValueAsync() w następujący sposób:

private void writeNewUser(string userId, string name, string email) {
    User user = new User(name, email);
    string json = JsonUtility.ToJson(user);

    mDatabaseRef.Child("users").Child(userId).SetRawJsonValueAsync(json);
}

Użycie SetValueAsync() lub SetRawJsonValueAsync() w ten sposób powoduje zastąpienie danych w określonej lokalizacji, łącznie ze wszystkimi węzłami podrzędnymi. Jednak nadal możesz zaktualizować element podrzędny bez przepisywania całego obiektu. Jeśli chcesz umożliwić użytkownikom aktualizację swoich profili, możesz zaktualizować nazwę użytkownika w następujący sposób:

mDatabaseRef.Child("users").Child(userId).Child("username").SetValueAsync(name);

Dołącz do listy danych

Użyj metody Push() , aby dołączyć dane do listy w aplikacjach obsługujących wielu użytkowników. Metoda Push() generuje unikalny klucz za każdym razem, gdy do określonego odniesienia Firebase dodawany jest nowy element podrzędny. Używając automatycznie generowanych kluczy dla każdego nowego elementu na liście, kilku klientów może dodać elementy podrzędne do tej samej lokalizacji w tym samym czasie, bez konfliktów zapisu. Unikalny klucz generowany przez Push() opiera się na znaczniku czasu, więc elementy listy są automatycznie porządkowane chronologicznie.

Możesz użyć odwołania do nowych danych zwróconych przez metodę Push() , aby uzyskać wartość automatycznie wygenerowanego klucza potomka lub ustawić dane dla potomka. Wywołanie Key w odniesieniu do Push() zwraca wartość automatycznie wygenerowanego klucza.

Zaktualizuj określone pola

Aby jednocześnie pisać do określonych węzłów podrzędnych węzła bez nadpisywania innych węzłów podrzędnych, użyj metody UpdateChildrenAsync() .

Podczas wywoływania funkcji UpdateChildrenAsync() można zaktualizować wartości podrzędne niższego poziomu, określając ścieżkę do klucza. Jeśli dane są przechowywane w wielu lokalizacjach w celu lepszego skalowania, możesz zaktualizować wszystkie wystąpienia tych danych, korzystając z rozdzielania danych . Na przykład gra może mieć klasę LeaderboardEntry taką jak ta:

public class LeaderboardEntry {
    public string uid;
    public int score = 0;

    public LeaderboardEntry() {
    }

    public LeaderboardEntry(string uid, int score) {
        this.uid = uid;
        this.score = score;
    }

    public Dictionary<string, Object> ToDictionary() {
        Dictionary<string, Object> result = new Dictionary<string, Object>();
        result["uid"] = uid;
        result["score"] = score;

        return result;
    }
}

Aby utworzyć wpis LeaderboardEntry i jednocześnie zaktualizować go do najnowszego źródła wyników i własnej listy wyników użytkownika, gra używa następującego kodu:

private void WriteNewScore(string userId, int score) {
    // Create new entry at /user-scores/$userid/$scoreid and at
    // /leaderboard/$scoreid simultaneously
    string key = mDatabase.Child("scores").Push().Key;
    LeaderBoardEntry entry = new LeaderBoardEntry(userId, score);
    Dictionary<string, Object> entryValues = entry.ToDictionary();

    Dictionary<string, Object> childUpdates = new Dictionary<string, Object>();
    childUpdates["/scores/" + key] = entryValues;
    childUpdates["/user-scores/" + userId + "/" + key] = entryValues;

    mDatabase.UpdateChildrenAsync(childUpdates);
}

W tym przykładzie zastosowano Push() w celu utworzenia wpisu w węźle zawierającego wpisy dla wszystkich użytkowników w /scores/$key i jednoczesnego pobrania klucza za pomocą Key . Klucza można następnie użyć do utworzenia drugiego wpisu w wynikach użytkownika pod /user-scores/$userid/$key .

Korzystając z tych ścieżek, można wykonywać jednoczesne aktualizacje wielu lokalizacji w drzewie JSON za pomocą jednego wywołania metody UpdateChildrenAsync() , na przykład w ten sposób, jak w tym przykładzie tworzy się nowy wpis w obu lokalizacjach. Jednoczesne aktualizacje wykonane w ten sposób mają charakter niepodzielny: albo wszystkie aktualizacje się powiodą, albo wszystkie aktualizacje nie powiodą się.

Usunąć dane

Najprostszym sposobem usunięcia danych jest wywołanie metody RemoveValue() w odniesieniu do lokalizacji tych danych.

Można również usunąć, określając null jako wartość innej operacji zapisu, takiej jak SetValueAsync() lub UpdateChildrenAsync() . Możesz użyć tej techniki z UpdateChildrenAsync() , aby usunąć wiele elementów podrzędnych w jednym wywołaniu interfejsu API.

Dowiedz się, kiedy Twoje dane są przekazywane.

Aby wiedzieć, kiedy Twoje dane zostaną zapisane na serwerze bazy danych Firebase Realtime Database, możesz dodać kontynuację. Zarówno SetValueAsync() jak i UpdateChildrenAsync() zwracają Task , które pozwala dowiedzieć się, kiedy operacja zostanie ukończona. Jeżeli z jakiegokolwiek powodu wywołanie zakończy się niepowodzeniem, parametr Tasks IsFaulted będzie miał wartość true, a właściwość Exception będzie wskazywała przyczynę wystąpienia niepowodzenia.

Zapisz dane jako transakcje

Podczas pracy z danymi, które mogą zostać uszkodzone przez jednoczesne modyfikacje, takie jak liczniki przyrostowe, można użyć operacji transakcyjnej . Nadajesz tej operacji Func . Ta aktualizacja Func przyjmuje bieżący stan danych jako argument i zwraca nowy żądany stan, który chcesz zapisać. Jeśli inny klient zapisuje do lokalizacji przed pomyślnym zapisaniem nowej wartości, funkcja aktualizacji zostanie wywołana ponownie z nową bieżącą wartością i ponowienie próby zapisu.

Na przykład w grze możesz pozwolić użytkownikom na aktualizację tabeli liderów z pięcioma najwyższymi wynikami:

private void AddScoreToLeaders(string email, 
                               long score,
                               DatabaseReference leaderBoardRef) {

    leaderBoardRef.RunTransaction(mutableData => {
      List<object> leaders = mutableData.Value as List<object>

      if (leaders == null) {
        leaders = new List<object>();
      } else if (mutableData.ChildrenCount >= MaxScores) {
        long minScore = long.MaxValue;
        object minVal = null;
        foreach (var child in leaders) {
          if (!(child is Dictionary<string, object>)) continue;
          long childScore = (long)
                      ((Dictionary<string, object>)child)["score"];
          if (childScore < minScore) {
            minScore = childScore;
            minVal = child;
          }
        }
        if (minScore > score) {
          // The new score is lower than the existing 5 scores, abort.
          return TransactionResult.Abort();
        }

        // Remove the lowest score.
        leaders.Remove(minVal);
      }

      // Add the new high score.
      Dictionary<string, object> newScoreMap =
                       new Dictionary<string, object>();
      newScoreMap["score"] = score;
      newScoreMap["email"] = email;
      leaders.Add(newScoreMap);
      mutableData.Value = leaders;
      return TransactionResult.Success(mutableData);
    });
}

Korzystanie z transakcji zapobiega błędom w tabeli liderów, jeśli wielu użytkowników rejestruje wyniki w tym samym czasie lub klient ma nieaktualne dane. Jeżeli transakcja zostanie odrzucona, serwer zwraca aktualną wartość klientowi, który ponownie uruchamia transakcję ze zaktualizowaną wartością. Powtarza się to do momentu zaakceptowania transakcji lub podjęcia zbyt wielu prób.

Zapisuj dane w trybie offline

Jeśli klient utraci połączenie sieciowe, Twoja aplikacja będzie nadal działać poprawnie.

Każdy klient podłączony do bazy danych Firebase utrzymuje własną wewnętrzną wersję wszelkich aktywnych danych. Kiedy dane są zapisywane, są najpierw zapisywane w tej wersji lokalnej. Następnie klient Firebase synchronizuje te dane ze zdalnymi serwerami baz danych i innymi klientami, dokładając wszelkich starań.

W rezultacie wszystkie zapisy do bazy danych natychmiast wyzwalają zdarzenia lokalne, zanim jakiekolwiek dane zostaną zapisane na serwerze. Oznacza to, że Twoja aplikacja pozostaje responsywna niezależnie od opóźnienia sieci lub łączności.

Po ponownym nawiązaniu połączenia aplikacja odbiera odpowiedni zestaw zdarzeń, dzięki czemu klient synchronizuje się z bieżącym stanem serwera bez konieczności pisania żadnego niestandardowego kodu.

Następne kroki