حفظ البيانات

قبل ان تبدأ

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

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

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

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

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

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

حفظ البيانات

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

طريقة الاستخدامات الشائعة
SetValueAsync() اكتب البيانات أو استبدلها بمسار محدد ، مثل users/<user-id>/<username> .
SetRawJsonValueAsync() اكتب البيانات أو استبدلها بـ Raw 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() لحذف العديد من العناصر الفرعية في استدعاء واحد لواجهة برمجة التطبيقات.

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

لمعرفة متى يتم ربط بياناتك بخادم قاعدة بيانات Firebase Realtime ، يمكنك إضافة متابعة. يقوم كل من 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 بعد ذلك بمزامنة تلك البيانات مع خوادم قاعدة البيانات البعيدة ومع العملاء الآخرين على أساس "أفضل جهد".

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

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

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