Zapisz dane

Zanim zaczniesz

Zanim zaczniesz korzystać z Realtime Database, musisz:

  • Zarejestruj projekt Unity i skonfiguruj go tak, aby korzystał z Firebase.

    • Jeśli Twój projekt w Unity korzysta już z Firebase, jest on już zarejestrowany i skonfigurowany pod kątem Firebase.

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

  • Dodaj do projektu Unity pakiet Firebase Unity SDK (a konkretnie FirebaseDatabase.unitypackage).

Pamiętaj, że dodanie Firebase do projektu w Unity wymaga wykonania czynności zarówno w Firebasekonsoli, jak i w otwartym projekcie w Unity (np. pobierasz z konsoli pliki konfiguracyjne Firebase, a następnie przenosisz je do projektu w Unity).

Zapisywanie danych

Dane można zapisywać w Firebase Realtime Database na 5 sposobów:

Metoda Typowe zastosowania
SetValueAsync() Zapisuj lub zastępuj dane w określonej ścieżce, np.users/<user-id>/<username>.
SetRawJsonValueAsync() Zapisywanie lub zastępowanie danych za pomocą nieprzetworzonego kodu JSON, np. users/<user-id>/<username>.
Push() Dodaj do listy danych. Za każdym razem, gdy wywołujesz funkcję Push(), Firebase generuje unikalny klucz, który może być też używany jako unikalny identyfikator, np. user-scores/<user-id>/<unique-score-id>.
UpdateChildrenAsync() zaktualizować niektóre klucze dla określonej ścieżki bez zastępowania wszystkich danych;
RunTransaction() Aktualizowanie złożonych danych, które mogą zostać uszkodzone przez równoczesne aktualizacje.

Pobieranie DatabaseReference

Aby zapisywać 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;
  }
}

Zapisywanie, aktualizowanie i usuwanie danych w referencji

Podstawowe operacje zapisu

W przypadku podstawowych operacji zapisu możesz użyć funkcji SetValueAsync(), aby zapisać dane w określonym odwołaniu, zastępując wszystkie istniejące dane w tej ścieżce. Za pomocą tej metody możesz przekazywać typy odpowiadające dostępnym typom JSON w ten sposób:

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

Jeśli używasz obiektu C# z określonym typem, możesz użyć wbudowanej funkcji JsonUtility.ToJson(), aby przekonwertować obiekt na surowy format JSON i wywołać funkcję SetRawJsonValueAsync(). Możesz na przykład mieć klasę User, która wygląda tak:

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

    public User() {
    }

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

Użytkownika z adresem SetRawJsonValueAsync() możesz dodać w ten 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, w tym wszystkich węzłów podrzędnych. Możesz jednak zaktualizować dziecko bez przepisywania całego obiektu. Jeśli chcesz zezwolić użytkownikom na aktualizowanie profili, możesz zaktualizować nazwę użytkownika w ten sposób:

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

Dołączanie do listy danych

Użyj metody Push(), aby dołączyć dane do listy w aplikacjach wielodostępnych. Metoda Push() generuje unikalny klucz za każdym razem, gdy do określonego odwołania Firebase dodawane jest nowe dziecko. Dzięki używaniu tych automatycznie generowanych kluczy dla każdego nowego elementu na liście kilku klientów może dodawać elementy podrzędne do tej samej lokalizacji w tym samym czasie bez konfliktów zapisu. Klucz unikalny generowany przez Push() jest oparty na sygnaturze czasowej, 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 elementu podrzędnego lub ustawić dane elementu podrzędnego. Wywołanie Key w przypadku odwołania Push() zwraca wartość klucza wygenerowanego automatycznie.

Aktualizowanie określonych pól

Aby jednocześnie zapisywać dane w określonych węzłach podrzędnych węzła bez zastępowania innych węzłów podrzędnych, użyj metody UpdateChildrenAsync().

Podczas wywoływania funkcji UpdateChildrenAsync() możesz aktualizować wartości podrzędne niższego poziomu, podając ścieżkę do klucza. Jeśli dane są przechowywane w wielu lokalizacjach, aby zapewnić lepszą skalowalność, możesz zaktualizować wszystkie ich wystąpienia za pomocą rozsyłania danych. Na przykład gra może mieć klasę LeaderboardEntry w tym stylu:

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&ltstring, Object&gt ToDictionary() {
        Dictionary&ltstring, Object&gt result = new Dictionary&ltstring, Object&gt();
        result["uid"] = uid;
        result["score"] = score;

        return result;
    }
}

Aby utworzyć obiekt LeaderboardEntry i jednocześnie zaktualizować go w kanale najnowszych wyników oraz na liście wyników użytkownika, gra używa kodu takiego jak ten:

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&ltstring, Object&gt entryValues = entry.ToDictionary();

    Dictionary&ltstring, Object&gt childUpdates = new Dictionary&ltstring, Object&gt();
    childUpdates["/scores/" + key] = entryValues;
    childUpdates["/user-scores/" + userId + "/" + key] = entryValues;

    mDatabase.UpdateChildrenAsync(childUpdates);
}

W tym przykładzie użyto Push(), aby utworzyć wpis w węźle zawierającym wpisy wszystkich użytkowników w /scores/$key, i jednocześnie pobrać klucz za pomocą Key. Klucz może być następnie użyty do utworzenia drugiego wpisu w wynikach użytkownika na stronie /user-scores/$userid/$key.

Korzystając z tych ścieżek, możesz jednocześnie aktualizować wiele lokalizacji w drzewie JSON za pomocą jednego wywołania UpdateChildrenAsync(). Na przykład w tym przykładzie tworzymy nowy wpis w obu lokalizacjach. Jednoczesne aktualizacje przeprowadzane w ten sposób są niepodzielne: wszystkie aktualizacje się udają lub wszystkie się nie udają.

Usuń dane

Najprostszym sposobem usunięcia danych jest wywołanie funkcji RemoveValue() na odwołaniu do lokalizacji tych danych.

Możesz też usunąć wartość, podając null w przypadku innej operacji zapisu, np. SetValueAsync() lub UpdateChildrenAsync(). Możesz użyć tej techniki z UpdateChildrenAsync(), aby usunąć wiele elementów podrzędnych w ramach jednego wywołania interfejsu API.

Dowiedz się, kiedy Twoje dane zostaną zatwierdzone.

Aby wiedzieć, kiedy dane zostaną przesłane na serwer Firebase Realtime Database, możesz dodać kontynuację. Zarówno SetValueAsync(), jak i UpdateChildrenAsync() zwracają Task, który pozwala sprawdzić, kiedy operacja zostanie zakończona. Jeśli z jakiegokolwiek powodu wywołanie zakończy się niepowodzeniem, wartość Tasks IsFaulted będzie równa „true”, a właściwość Exception będzie wskazywać przyczynę niepowodzenia.

Zapisywanie danych jako transakcji

W przypadku danych, które mogą zostać uszkodzone przez równoczesne modyfikacje, np. liczników przyrostowych, możesz użyć operacji transakcji. Nadaj tej operacji Func. Ta funkcja Func przyjmuje jako argument bieżący stan danych i zwraca nowy, pożądany stan, który chcesz zapisać. Jeśli inny klient zapisze dane w lokalizacji, zanim nowa wartość zostanie zapisana, funkcja aktualizacji zostanie ponownie wywołana z nową bieżącą wartością, a zapis zostanie ponowiony.

Na przykład w grze możesz zezwolić użytkownikom na aktualizowanie tablicy wyników 5 najlepszymi wynikami:

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

    leaderBoardRef.RunTransaction(mutableData =&gt {
      List&ltobject&gt leaders = mutableData.Value as List&ltobject>

      if (leaders == null) {
        leaders = new List&ltobject&gt();
      } else if (mutableData.ChildrenCount &gt= MaxScores) {
        long minScore = long.MaxValue;
        object minVal = null;
        foreach (var child in leaders) {
          if (!(child is Dictionary&ltstring, object&gt)) continue;
          long childScore = (long)
                      ((Dictionary&ltstring, object&gt)child)["score"];
          if (childScore &lt minScore) {
            minScore = childScore;
            minVal = child;
          }
        }
        if (minScore &gt 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&ltstring, object&gt newScoreMap =
                       new Dictionary&ltstring, object&gt();
      newScoreMap["score"] = score;
      newScoreMap["email"] = email;
      leaders.Add(newScoreMap);
      mutableData.Value = leaders;
      return TransactionResult.Success(mutableData);
    });
}

Użycie transakcji zapobiega nieprawidłowemu wyświetlaniu tablicy wyników, jeśli wielu użytkowników zarejestruje wyniki w tym samym czasie lub klient miał nieaktualne dane. Jeśli transakcja zostanie odrzucona, serwer zwróci bieżącą wartość do klienta, który ponownie uruchomi transakcję ze zaktualizowaną wartością. Powtarzaj te czynności, aż transakcja zostanie zaakceptowana lub wykonasz zbyt wiele prób.

Zapisywanie danych offline

Jeśli klient utraci połączenie z siecią, aplikacja będzie nadal działać prawidłowo.

Każdy klient połączony z bazą danych Firebase ma własną wewnętrzną wersję aktywnych danych. Gdy dane są zapisywane, najpierw trafiają do tej lokalnej wersji. Klient Firebase synchronizuje te dane z serwerami zdalnej bazy danych i innymi klientami w miarę możliwości.

W rezultacie wszystkie zapisy w bazie danych natychmiast wywołują zdarzenia lokalne, zanim jakiekolwiek dane zostaną zapisane na serwerze. Oznacza to, że aplikacja pozostaje responsywna niezależnie od opóźnienia sieci lub połączenia.

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

Następne kroki