حفظ البيانات

قبل البدء

لاستخدام Realtime Database، عليك إجراء ما يلي:

  • سجِّل مشروع Unity وأعدّه لاستخدام Firebase.

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

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

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

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

حفظ البيانات

هناك خمس طرق لكتابة البيانات في Firebase Realtime Database:

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

الحصول على DatabaseReference

لكتابة البيانات في قاعدة البيانات، تحتاج إلى مثيل من 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(). على سبيل المثال، قد يكون لديك فئة User بالشكل التالي:

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 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 هذه البيانات مع قاعدة بيانات المشغّلات البعيدة ومع برامج أخرى على أساس "أقصى جهد".

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

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

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