حفظ البيانات

قبل ان تبدأ

قبل أن تتمكن من استخدام Realtime Database ، تحتاج إلى:

  • قم بتسجيل مشروع Unity الخاص بك وقم بتكوينه لاستخدام Firebase.

    • إذا كان مشروع Unity الخاص بك يستخدم Firebase بالفعل، فهذا يعني أنه تم تسجيله وتكوينه بالفعل لـ Firebase.

    • إذا لم يكن لديك مشروع Unity، فيمكنك تنزيل تطبيق نموذجي .

  • أضف Firebase Unity SDK (على وجه التحديد، FirebaseDatabase.unitypackage ) إلى مشروع Unity الخاص بك.

لاحظ أن إضافة Firebase إلى مشروع Unity الخاص بك يتضمن مهام في كل من وحدة تحكم Firebase وفي مشروع Unity المفتوح (على سبيل المثال، يمكنك تنزيل ملفات تكوين Firebase من وحدة التحكم، ثم نقلها إلى مشروع Unity الخاص بك).

حفظ البيانات

هناك خمس طرق لكتابة البيانات إلى قاعدة بيانات Firebase Realtime:

طريقة الاستخدامات الشائعة
SetValueAsync() كتابة البيانات أو استبدالها في مسار محدد، مثل users/<user-id>/<username> .
SetRawJsonValueAsync() اكتب البيانات أو استبدلها بـ Json الخام، مثل users/<user-id>/<username> .
Push() أضف إلى قائمة البيانات. في كل مرة تتصل فيها بـ Push() ، يُنشئ Firebase مفتاحًا فريدًا يمكن استخدامه أيضًا كمعرف فريد، مثل user-scores/<user-id>/<unique-score-id> .
UpdateChildrenAsync() قم بتحديث بعض المفاتيح لمسار محدد دون استبدال كافة البيانات.
RunTransaction() قم بتحديث البيانات المعقدة التي قد تتلف بسبب التحديثات المتزامنة.

الحصول على مرجع قاعدة البيانات

لكتابة البيانات إلى قاعدة البيانات، تحتاج إلى مثيل 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;
  }
}

كتابة البيانات أو تحديثها أو حذفها في مرجع

عمليات الكتابة الأساسية

بالنسبة لعمليات الكتابة الأساسية، يمكنك استخدام SetValueAsync() لحفظ البيانات في مرجع محدد، واستبدال أي بيانات موجودة في هذا المسار. يمكنك استخدام هذه الطريقة لتمرير الأنواع التي تتوافق مع أنواع JSON المتوفرة كما يلي:

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

إذا كنت تستخدم كائن C# مكتوبًا، فيمكنك استخدام JsonUtility.ToJson() المضمن لتحويل الكائن إلى Json خام واستدعاء SetRawJsonValueAsync() . على سبيل المثال، قد يكون لديك فئة المستخدم التي تبدو كما يلي:

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

    public User() {
    }

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

يمكنك إضافة مستخدم باستخدام SetRawJsonValueAsync() كما يلي:

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);
}

يؤدي استخدام SetValueAsync() أو SetRawJsonValueAsync() بهذه الطريقة إلى الكتابة فوق البيانات في الموقع المحدد، بما في ذلك أي عقد فرعية. ومع ذلك، لا يزال بإمكانك تحديث كائن فرعي دون إعادة كتابة الكائن بأكمله. إذا كنت تريد السماح للمستخدمين بتحديث ملفاتهم الشخصية، فيمكنك تحديث اسم المستخدم على النحو التالي:

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

إلحاق بقائمة البيانات

استخدم أسلوب Push() لإلحاق البيانات بقائمة في التطبيقات متعددة المستخدمين. تنشئ طريقة Push() مفتاحًا فريدًا في كل مرة تتم فيها إضافة طفل جديد إلى مرجع Firebase المحدد. باستخدام هذه المفاتيح التي تم إنشاؤها تلقائيًا لكل عنصر جديد في القائمة، يمكن للعديد من العملاء إضافة عناصر فرعية إلى نفس الموقع في نفس الوقت دون حدوث تعارضات في الكتابة. يعتمد المفتاح الفريد الذي تم إنشاؤه بواسطة Push() على طابع زمني، لذلك يتم ترتيب عناصر القائمة تلقائيًا بتسلسل زمني.

يمكنك استخدام المرجع إلى البيانات الجديدة التي يتم إرجاعها بواسطة طريقة Push() للحصول على قيمة المفتاح الذي تم إنشاؤه تلقائيًا للطفل أو تعيين البيانات للطفل. يؤدي استدعاء Key على مرجع Push() إلى إرجاع قيمة المفتاح الذي تم إنشاؤه تلقائيًا.

تحديث حقول محددة

للكتابة بشكل متزامن إلى فروع محددة لعقدة دون الكتابة فوق العقد الفرعية الأخرى، استخدم الأسلوب UpdateChildrenAsync() .

عند استدعاء UpdateChildrenAsync() ، يمكنك تحديث القيم الفرعية ذات المستوى الأدنى عن طريق تحديد مسار للمفتاح. إذا تم تخزين البيانات في مواقع متعددة لتوسيع نطاقها بشكل أفضل، فيمكنك تحديث جميع مثيلات تلك البيانات باستخدام توزيع البيانات . على سبيل المثال، قد تحتوي إحدى الألعاب على فئة LeaderboardEntry مثل هذا:

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;
    }
}

لإنشاء "LeaderboardEntry" وتحديثه في نفس الوقت إلى خلاصة النتائج الأخيرة وقائمة النتائج الخاصة بالمستخدم، تستخدم اللعبة رمزًا مثل هذا:

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);
}

يستخدم هذا المثال Push() لإنشاء إدخال في العقدة التي تحتوي على إدخالات لجميع المستخدمين في /scores/$key واسترداد المفتاح في نفس الوقت باستخدام Key . يمكن بعد ذلك استخدام المفتاح لإنشاء إدخال ثانٍ في نتائج المستخدم على /user-scores/$userid/$key .

باستخدام هذه المسارات، يمكنك إجراء تحديثات متزامنة لمواقع متعددة في شجرة JSON من خلال استدعاء واحد لـ UpdateChildrenAsync() ، مثل كيفية إنشاء هذا المثال للإدخال الجديد في كلا الموقعين. التحديثات المتزامنة التي يتم إجراؤها بهذه الطريقة تكون ذرية: إما أن تنجح كافة التحديثات أو تفشل كافة التحديثات.

حذف البيانات

إن أبسط طريقة لحذف البيانات هي استدعاء RemoveValue() على مرجع لموقع تلك البيانات.

يمكنك أيضًا الحذف عن طريق تحديد null كقيمة لعملية كتابة أخرى مثل SetValueAsync() أو UpdateChildrenAsync() . يمكنك استخدام هذه التقنية مع UpdateChildrenAsync() لحذف عدة توابع في استدعاء API واحد.

اعرف متى يتم الالتزام ببياناتك.

لمعرفة متى يتم إرسال بياناتك إلى خادم Firebase Realtime Database، يمكنك إضافة متابعة. يقوم كل من SetValueAsync() و UpdateChildrenAsync() بإرجاع Task تسمح لك بمعرفة وقت اكتمال العملية. إذا لم ينجح الاستدعاء لأي سبب من الأسباب، فستكون المهام IsFaulted صحيحة مع الإشارة إلى خاصية Exception بسبب حدوث الفشل.

حفظ البيانات كمعاملات

عند العمل مع البيانات التي قد تتلف بسبب التعديلات المتزامنة، مثل العدادات التزايدية، يمكنك استخدام عملية المعاملة . أنت تعطي هذه العملية Func . يأخذ هذا التحديث Func الحالة الحالية للبيانات كوسيطة ويعيد الحالة الجديدة المطلوبة التي ترغب في كتابتها. إذا كتب عميل آخر إلى الموقع قبل كتابة القيمة الجديدة بنجاح، فسيتم استدعاء وظيفة التحديث الخاصة بك مرة أخرى بالقيمة الحالية الجديدة، وتتم إعادة محاولة الكتابة.

على سبيل المثال، في إحدى الألعاب، يمكنك السماح للمستخدمين بتحديث لوحة المتصدرين بأعلى خمس نقاط:

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);
    });
}

يؤدي استخدام المعاملة إلى منع لوحة المتصدرين من أن تكون غير صحيحة إذا قام عدة مستخدمين بتسجيل النتائج في نفس الوقت أو كان لدى العميل بيانات قديمة. إذا تم رفض المعاملة، يقوم الخادم بإرجاع القيمة الحالية إلى العميل، الذي يقوم بتشغيل المعاملة مرة أخرى بالقيمة المحدثة. يتكرر هذا حتى يتم قبول المعاملة أو إجراء عدد كبير جدًا من المحاولات.

كتابة البيانات دون اتصال

إذا فقد العميل اتصاله بالشبكة، فسيستمر تطبيقك في العمل بشكل صحيح.

يحتفظ كل عميل متصل بقاعدة بيانات Firebase بنسخته الداخلية الخاصة من أي بيانات نشطة. عند كتابة البيانات، يتم كتابتها إلى هذا الإصدار المحلي أولاً. يقوم عميل Firebase بعد ذلك بمزامنة تلك البيانات مع خوادم قاعدة البيانات البعيدة ومع العملاء الآخرين على أساس "أفضل جهد".

ونتيجة لذلك، تؤدي جميع عمليات الكتابة إلى قاعدة البيانات إلى تشغيل الأحداث المحلية على الفور، قبل كتابة أي بيانات إلى الخادم. وهذا يعني أن تطبيقك يظل مستجيبًا بغض النظر عن زمن وصول الشبكة أو اتصالها.

بمجرد إعادة تأسيس الاتصال، يتلقى تطبيقك المجموعة المناسبة من الأحداث بحيث يتزامن العميل مع حالة الخادم الحالية، دون الحاجة إلى كتابة أي تعليمات برمجية مخصصة.

الخطوات التالية