تنفيذ عمليات تعديل البيانات في Data Connect

تتيح لك Firebase Data Connect إنشاء موصّلات لمثيلات PostgreSQL التي تتم إدارتها باستخدام Google Cloud SQL. هذه الوصلات هي مجموعات من طلبات البحث وعمليات التعديل لاستخدام بياناتك من المخطط.

قدّم دليل البدء مخططًا لتطبيق مراجعات الأفلام خاصًا بـ PostgreSQL.

قدّم هذا الدليل أيضًا العمليات الإدارية القابلة للنشر والمخصّصة، بما في ذلك عمليات التعديل.

  • التعديلات القابلة للنشر هي التعديلات التي تنفّذها لإجراء مكالمات من تطبيقات العميل في موصّل، مع نقاط نهاية لواجهة برمجة التطبيقات تحدّدها أنت. تدمج Data Connect المصادقة والتفويض في عمليات التغيير هذه، وتنشئ حِزم SDK للبرامج استنادًا إلى واجهة برمجة التطبيقات.
  • يتم تنفيذ التغييرات الإدارية المخصّصة من بيئات ذات امتيازات لتعبئة الجداول وإدارتها. يمكنك إنشاء هذه الطلبات وتنفيذها في وحدة تحكّم Firebase، ومن بيئات ذات امتيازات باستخدام Firebase Admin SDK، وفي بيئات التطوير المحلية باستخدام إضافة Data Connect في VS Code.

يقدّم هذا الدليل نظرة أعمق على التغييرات القابلة للنشر.

ميزات عمليات التحوّل في Data Connect

تتيح لك Data Connect إجراء عمليات تعديل أساسية بجميع الطرق التي تتوقّعها عند استخدام قاعدة بيانات PostgreSQL:

  • تنفيذ عمليات CRUD
  • إدارة العمليات المتعددة الخطوات باستخدام المعاملات

ولكن باستخدام إضافات Data Connect إلى GraphQL، يمكنك تنفيذ عمليات تغيير متقدّمة لإنشاء تطبيقات أسرع وأكثر فعالية:

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

استخدام الحقول التي تم إنشاؤها لتنفيذ عمليات تغيير

ستوسّع عمليات Data Connect مجموعة من الحقول التي يتم إنشاؤها تلقائيًا Data Connect استنادًا إلى الأنواع وعلاقات الأنواع في المخطط. يتم إنشاء هذه الحقول بواسطة أدوات محلية عند تعديل المخطط.

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

لنفترض أنّ المخطط يتضمّن نوع Movie ونوع Actor مرتبطًا به. تنشئ Data Connect الحقول movie_insert وmovie_update وmovie_delete وغيرها.

التغيير باستخدام الحقل
movie_insert

يمثّل الحقل movie_insert عملية تغيير لإنشاء سجلّ واحد في الجدول Movie.

استخدِم هذا الحقل لإنشاء فيلم واحد.

mutation CreateMovie($data: Movie_Data!) {
  movie_insert(data: $data) { key }
}

التغيير باستخدام الحقل
movie_update

يمثّل الحقل movie_update عملية تغيير لتعديل سجلّ واحد في الجدول Movie.

استخدِم هذا الحقل لتعديل فيلم واحد باستخدام مفتاحه.

mutation UpdateMovie($myKey: Movie_Key!, $data: Movie_Data!) {
  movie_update(key: $myKey, data: $data) { key }
}

التغيير باستخدام الحقل
movie_delete

يمثّل الحقل movie_delete عملية تغيير لحذف سجلّ واحد في الجدول Movie.

استخدِم هذا الحقل لحذف فيلم واحد باستخدام مفتاحه.

  mutation DeleteMovie($myKey: Movie_Key!) {
    movie_delete(key: $myKey) { key }
  }

العناصر الأساسية لعملية التحوّل

تعدّ عمليات التغيير في Data Connect عمليات تغيير في GraphQL تتضمّن Data Connectإضافات. كما هو الحال مع عملية تعديل GraphQL عادية، يمكنك تحديد اسم عملية وقائمة بمتغيرات GraphQL.

توسّع Data Connect طلبات بحث GraphQL باستخدام توجيهات مخصّصة، مثل @auth و@transaction.

لذلك، يتضمّن التغيير التالي:

  • تعريف نوع mutation
  • اسم عملية SignUp (تغيير)
  • وسيطة عملية $username لمتغيّر واحد
  • توجيه واحد، @auth
  • حقل واحد user_insert
mutation SignUp($username: String!) @auth(level: USER) {
  user_insert(data: {
    id_expr: "auth.uid"
    username: $username
  })
}

تتطلّب كل وسيطة تغيير تعريف نوع، سواء كان نوعًا مضمّنًا مثل String، أو نوعًا مخصّصًا محدّدًا في المخطط مثل Movie.

كتابة الطفرات الأساسية

يمكنك البدء في كتابة عمليات تغيير لإنشاء سجلّات فردية وتعديلها وحذفها من قاعدة البيانات.

إنشاء

لننفّذ عمليات إنشاء أساسية.

# Create a movie based on user input
mutation CreateMovie($title: String!, $releaseYear: Int!, $genre: String!, $rating: Int!) {
  movie_insert(data: {
    title: $title
    releaseYear: $releaseYear
    genre: $genre
    rating: $rating
  })
}

# Create a movie with default values
mutation CreateMovie2 {
  movie_insert(data: {
    title: "Sherlock Holmes"
    releaseYear: 2009
    genre: "Mystery"
    rating: 5
  })
}

أو عملية إدراج/تعديل.

# Movie upsert using combination of variables and literals
mutation UpsertMovie($title: String!) {
  movie_upsert(data: {
    title: $title
    releaseYear: 2009
    genre: "Mystery"
    rating: 5
    genre: "Mystery/Thriller"
  })
}

تنفيذ التحديثات

في ما يلي التعديلات. من المؤكد أنّ المنتجين والمخرجين يأملون أن تكون هذه التقييمات المتوسطة ضمن المعدل المتوقع.

يحتوي الحقل movie_update على وسيطة id متوقّعة لتحديد سجلّ وحقل data يمكنك استخدامه لضبط القيم في هذا التعديل.

mutation UpdateMovie(
  $id: UUID!,
  $genre: String!,
  $rating: Int!,
  $description: String!
) {
  movie_update(id: $id,
    data: {
      genre: $genre
      rating: $rating
      description: $description
    })
}

لإجراء تعديلات متعددة، استخدِم الحقل movie_updateMany.

# Multiple updates (increase all ratings of a genre)
mutation IncreaseRatingForGenre($genre: String!, $rating: Int!) {
  movie_updateMany(
    where: { genre: { eq: $genre } },
    data:
      {
        rating: $rating
      })
}

استخدام عمليات الزيادة والنقصان والإلحاق والإضافة في البداية مع _update

في حين أنّه يمكنك ضبط القيم بشكل صريح في عمليات التعديل _update و_updateMany ضمن data:، من الأفضل غالبًا تطبيق عامل تشغيل مثل الزيادة لتعديل القيم.

لتعديل مثال التعديل السابق، افترض أنّك تريد زيادة تقييم فيلم معيّن. يمكنك استخدام بنية rating_update مع عامل التشغيل inc.

mutation UpdateMovie(
  $id: UUID!,
  $ratingIncrement: Int!
) {
  movie_update(id: $id, data: {
    rating_update: {
      inc: $ratingIncrement
    }
  })
}

تتيح Data Connect استخدام عوامل التشغيل التالية لتعديل الحقول:

  • inc لزيادة أنواع البيانات Int وInt64 وFloat وDate وTimestamp
  • dec لتقليل أنواع البيانات Int وInt64 وFloat وDate وTimestamp

بالنسبة إلى القوائم، يمكنك أيضًا تعديلها باستخدام قيم فردية أو قوائم قيم باستخدام:

  • add لإلحاق عناصر إذا لم تكن موجودة في أنواع القوائم، باستثناء قوائم Vector
  • remove لإزالة جميع العناصر، إذا كانت متوفرة، من أنواع القوائم باستثناء قوائم المتجهات
  • append لإلحاق عناصر بأنواع القوائم، باستثناء قوائم Vector
  • prepend لإضافة عناصر إلى بداية أنواع القوائم، باستثناء قوائم المتجهات

تنفيذ عمليات الحذف

يمكنك بالطبع حذف بيانات الأفلام. من المؤكد أنّ خبراء الحفاظ على الأفلام يريدون الحفاظ على الأفلام المادية لأطول فترة ممكنة.

# Delete by key
mutation DeleteMovie($id: UUID!) {
  movie_delete(id: $id)
}

يمكنك هنا استخدام _deleteMany.

# Multiple deletes
mutation DeleteUnpopularMovies($minRating: Int!) {
  movie_deleteMany(where: { rating: { le: $minRating } })
}

كتابة عمليات تغيير في العلاقات

تعرَّف على كيفية استخدام عملية التغيير الضمنية _upsert في علاقة.

# Create or update a one to one relation
mutation MovieMetadataUpsert($movieId: UUID!, $director: String!) {
  movieMetadata_upsert(
    data: { movie: { id: $movieId }, director: $director }
  )
}

تصميم المخططات لتعديلات فعّالة

توفّر Data Connect ميزتَين مهمتَين تتيحان لك كتابة عمليات تغيير أكثر كفاءة وتوفير عمليات الرحلة ذهابًا وإيابًا.

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

باستخدام قيم الخادم، يمكنك السماح للخادم بملء الحقول في جداولك بشكل ديناميكي باستخدام القيم المخزّنة أو التي يمكن حسابها بسهولة وفقًا لتعبيرات CEL معيّنة من جهة الخادم في الوسيطة expr. على سبيل المثال، يمكنك تحديد حقل مع طابع زمني يتم تطبيقه عند الوصول إلى الحقل باستخدام الوقت المخزّن في طلب عملية، updatedAt: Timestamp! @default(expr: "request.time").

كتابة عمليات تغيير متقدّمة: السماح لـ Data Connect بتوفير القيم باستخدام بنية field_expr

كما هو موضّح في القيم العددية الأساسية وقيم الخادم، يمكنك تصميم المخطط الخاص بك بطريقة تتيح للخادم ملء قيم الحقول الشائعة مثل ids والتواريخ استجابةً لطلبات العميل.

بالإضافة إلى ذلك، يمكنك الاستفادة من البيانات، مثل أرقام تعريف المستخدمين، التي يتم إرسالها في عناصر Data Connect request من تطبيقات العميل.

عند تنفيذ عمليات تغيير، استخدِم بنية field_expr لتفعيل التعديلات التي ينشئها الخادم أو الوصول إلى البيانات من الطلبات. على سبيل المثال، لتمرير إذن الوصول uid المخزَّن في طلب إلى عملية _upsert، يجب تمرير "auth.uid" في الحقل userId_expr.

# Add a movie to the user's favorites list
mutation AddFavoritedMovie($movieId: UUID!) @auth(level: USER) {
  favorite_movie_upsert(data: { userId_expr: "auth.uid", movieId: $movieId })
}

# Remove a movie from the user's favorites list
mutation DeleteFavoritedMovie($movieId: UUID!) @auth(level: USER) {
  favorite_movie_delete(key: { userId_expr: "auth.uid", movieId: $movieId })
}

أو، في تطبيق مألوف لقوائم المهام، عند إنشاء قائمة مهام جديدة، يمكنك تمرير id_expr لتوجيه الخادم إلى إنشاء معرّف فريد عالميًا (UUID) تلقائيًا للقائمة.

mutation CreateTodoListWithFirstItem(
  $listName: String!
) @transaction {
  # Step 1
  todoList_insert(data: {
    id_expr: "uuidV4()", # <-- auto-generated. Or a column-level @default on `type TodoList` will also work
    name: $listName,
  })
}

لمزيد من المعلومات، راجِع قيم _Expr العددية في مرجع القيم العددية.

كتابة عمليات تغيير متقدّمة: عمليات متعدّدة الخطوات

هناك العديد من الحالات التي قد تحتاج فيها إلى تضمين حقول كتابة متعددة (مثل عمليات الإدراج) في عملية تغيير واحدة. قد تحتاج أيضًا إلى قراءة قاعدة البيانات أثناء تنفيذ عملية تغيير للبحث عن البيانات الحالية والتحقّق منها قبل إجراء عمليات، مثل الإدراج أو التعديل. توفّر هذه الخيارات عمليات الرحلة ذهابًا وإيابًا، وبالتالي التكاليف.

تتيح لك السمة Data Connect تنفيذ منطق متعدّد الخطوات في عمليات التغيير من خلال توفير ما يلي:

  • حقول كتابة متعددة

  • حقول قراءة متعدّدة في عمليات التغيير (باستخدام الكلمة الرئيسية للحقل query).

  • التوجيه @transaction الذي يوفّر إمكانية إجراء المعاملات كما هو الحال في قواعد البيانات العلائقية.

  • توجيه @check، الذي يتيح لك تقييم محتوى عمليات القراءة باستخدام تعابير CEL، واستنادًا إلى نتائج هذا التقييم:

    • المتابعة مع عمليات الإنشاء والتعديل والحذف المحدّدة بواسطة تغيير
    • المتابعة لإرجاع نتائج حقل طلب البحث
    • استخدام الرسائل التي تم إرجاعها لتنفيذ المنطق المناسب في رمز العميل
  • التوجيه @redact، الذي يتيح لك حذف نتائج حقل الطلب من نتائج بروتوكول النقل

  • ربط CEL response، الذي يخزّن النتائج المتراكمة لجميع عمليات التغيير والاستعلامات التي يتم تنفيذها في عملية معقّدة ومتعددة الخطوات يمكنك الوصول إلى عملية ربط حساب response باتّباع الخطوات التالية:

    • في توجيهات @check، من خلال الوسيطة expr:
    • باستخدام قيم الخادم، باستخدام بنية field_expr

توجيه @transaction

يتضمّن دعم عمليات التغيير المتعدّدة الخطوات معالجة الأخطاء باستخدام المعاملات.

يفرض التوجيه @transaction أن يتم دائمًا تنفيذ عملية تعديل - باستخدام حقل كتابة واحد (على سبيل المثال، _insert أو _update) أو باستخدام حقول كتابة متعددة - في معاملة قاعدة بيانات.

  • تنفّذ عمليات التغيير بدون @transaction كل حقل جذر بالتتابع. تعرض العملية أي أخطاء كأخطاء في الحقول الجزئية، ولكن ليس تأثيرات عمليات التنفيذ اللاحقة.

  • يُضمَن أن تؤدي عمليات التغيير التي تتضمّن @transaction إما إلى النجاح الكامل أو الفشل الكامل. إذا تعذّر تنفيذ أي من الحقول ضمن المعاملة، سيتم التراجع عن المعاملة بأكملها.

التوجيهان @check و@redact

يتحقّق الأمر @check من توفّر الحقول المحدّدة في نتائج البحث. يتم استخدام تعبير "لغة التعبير الشائعة" (CEL) لاختبار قيم الحقول. السلوك التلقائي للتوجيه هو البحث عن العُقد التي تكون قيمتها null أو [] (قوائم فارغة) ورفضها.

يؤدي التوجيه @redact إلى إخفاء جزء من الردّ عن العميل. تستمر عملية تقييم الحقول التي تم إخفاء بياناتها بحثًا عن آثار جانبية (بما في ذلك تغييرات البيانات و@check)، وتظل النتائج متاحة للخطوات اللاحقة في تعبيرات CEL.

استخدِم @check و@check(message:) و@redact.

يتم استخدام @check و@redact بشكل أساسي للبحث عن البيانات ذات الصلة من أجل تحديد ما إذا كان يجب السماح بعمليات معيّنة، وذلك باستخدام البحث في المنطق ولكن إخفائه عن العملاء. يمكن أن يعرض طلب البحث رسائل مفيدة للتعامل بشكل صحيح مع رمز العميل.

للتوضيح، يتحقّق حقل طلب البحث التالي مما إذا كان لدى مقدّم الطلب دور "مشرف" مناسب للاطّلاع على المستخدمين الذين يمكنهم تعديل فيلم.

query GetMovieEditors($movieId: UUID!) @auth(level: USER) {
  moviePermission(key: { movieId: $movieId, userId_expr: "auth.uid" }) @redact {
    role @check(expr: "this == 'admin'", message: "You must be an admin to view all editors of a movie.")
  }
  moviePermissions(where: { movieId: { eq: $movieId }, role: { eq: "editor" } }) {
    user {
      id
      username
    }
  }
}

لمزيد من المعلومات حول التوجيهَين @check و@redact في عمليات التحقّق من الأذونات، يُرجى الاطّلاع على مناقشة البحث عن بيانات الأذونات.

استخدام @check للتحقّق من صحة المفاتيح

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

لتجنُّب هذه النتيجة، اختبِر ما إذا كان يمكن العثور على المفاتيح باستخدام التوجيه @check.

# Delete by key, error if not found
mutation MustDeleteMovie($id: UUID!) @transaction {
  movie_delete(id: $id) @check(expr: "this != null", message: "Movie not found, therefore nothing is deleted")
}

استخدِم عملية الربط response لتسلسل عمليات التغيير المتعددة الخطوات

تتمثّل الطريقة الأساسية لإنشاء سجلّات ذات صلة، مثل Movie جديد وإدخال MovieMetadata مرتبط به، في ما يلي:

  1. استدعاء عملية تغيير _insert لـ Movie
  2. تخزين المفتاح الذي تم إرجاعه للفيلم الذي تم إنشاؤه
  3. بعد ذلك، استدعِ عملية تغيير _insert ثانية لإنشاء سجل MovieMetadata.

باستخدام Data Connect، يمكنك التعامل مع هذه الحالة الشائعة في عملية واحدة متعددة الخطوات من خلال الوصول إلى نتائج _insert الأولى في _insert الثانية.

يتطلّب إنشاء تطبيق ناجح لمراجعة الأفلام الكثير من العمل. لنتابع قائمة المهام الخاصة بنا باستخدام مثال جديد.

استخدام response لضبط الحقول باستخدام قيم الخادم

في عملية تعديل قائمة المهام التالية:

  • يمثّل الربط response عنصر الاستجابة الجزئية حتى الآن، والذي يتضمّن جميع حقول التعديل ذات المستوى الأعلى قبل الحقل الحالي.
  • يتم الوصول إلى نتائج عملية todoList_insert الأولية، التي تعرض الحقل id (المفتاح)، لاحقًا في response.todoList_insert.id حتى نتمكّن من إدراج عنصر جديد في قائمة المهام على الفور.
mutation CreateTodoListWithFirstItem(
  $listName: String!,
  $itemContent: String!
) @transaction {
  # Sub-step 1:
  todoList_insert(data: {
    id_expr: "uuidV4()", # <-- auto-generated. Or a column-level @default on `type TodoList` will also work
    name: $listName,
  })
  # Sub-step 2:
  todo_insert(data: {
    listId_expr: "response.todoList_insert.id" # <-- Grab the newly generated ID from the partial response so far.
    content: $itemContent,
  })
}

استخدام response للتحقّق من صحة الحقول باستخدام @check

يتوفّر response أيضًا في @check(expr: "...")، ما يتيح لك استخدامه لإنشاء منطق أكثر تعقيدًا من جهة الخادم. بالإضافة إلى query { … } خطوات في عمليات التغيير، يمكنك تحقيق المزيد بدون أي رحلات إضافية بين العميل والخادم.

في المثال التالي، لاحظ أنّ @check لديه إذن الوصول إلى response.query لأنّ @check يتم تنفيذه دائمًا بعد الخطوة التي تم إرفاقه بها.

mutation CreateTodoInNamedList(
  $listName: String!,
  $itemContent: String!
) @transaction {
  # Sub-step 1: Look up List.id by its name
  query
  @check(expr: "response.query.todoLists.size() > 0", message: "No such TodoList with the name!")
  @check(expr: "response.query.todoLists.size() < 2", message: "Ambiguous listName!") {
    todoLists(where: { name: $listName }) {
      id
    }
  }
  # Sub-step 2:
  todo_insert(data: {
    listId_expr: "response.todoLists[0].id" # <-- Now we have the parent list ID to insert to
    content: $itemContent,
  })
}

لمزيد من المعلومات حول ربط response، يُرجى الاطّلاع على مرجع CEL.

فهم العمليات التي تمّت مقاطعتها باستخدام @transaction وquery @check

قد تحدث أخطاء في عمليات التغيير المتعدّدة الخطوات:

  • قد يتعذّر تنفيذ عمليات قاعدة البيانات.
  • قد يؤدي منطق طلب البحث @check إلى إنهاء العمليات.

تقترح Data Connect استخدام توجيه @transaction مع عمليات التغيير المتعدّدة الخطوات. يؤدي ذلك إلى إنشاء قاعدة بيانات أكثر اتساقًا ونتائج تغييرات أسهل في التعامل معها في رمز العميل:

  • عند حدوث الخطأ الأول أو تعذُّر @check، سيتم إنهاء العملية، وبالتالي لن يكون هناك حاجة إلى إدارة تنفيذ أي حقول لاحقة أو تقييم CEL.
  • يتم تنفيذ عمليات التراجع استجابةً لأخطاء في قاعدة البيانات أو منطق @check، ما يؤدي إلى حالة متسقة لقاعدة البيانات.
  • يتم دائمًا عرض خطأ في التراجع عن التغييرات لرمز العميل.

قد تختار عدم استخدام @transaction في بعض حالات الاستخدام، مثلًا إذا كنت بحاجة إلى معدل نقل بيانات أعلى أو قابلية توسيع أو توفّر. ومع ذلك، عليك إدارة قاعدة البيانات ورمز العميل للسماح بعرض النتائج:

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

توجيهات لتغييرات Data Connect

بالإضافة إلى التوجيهات التي تستخدمها في تحديد الأنواع والجداول، يوفّر Data Connect التوجيهات @auth و@check و@redact و@transaction لتعزيز سلوك العمليات.

التوجيه ينطبق على الوصف
@auth الاستعلامات وعمليات التعديل تحدّد هذه السمة سياسة التفويض الخاصة بطلب بحث أو تعديل. يمكنك الاطّلاع على دليل التفويض والتصديق.
@check query الحقول في العمليات المتعددة الخطوات تتحقّق هذه السمة من توفّر الحقول المحدّدة في نتائج طلب البحث. يتم استخدام تعبير بلغة التعبير الشائعة (CEL) لاختبار قيم الحقول. اطّلِع على العمليات المتعدّدة الخطوات.
@redact طلبات البحث يخفي جزءًا من الردّ عن العميل. اطّلِع على العمليات المتعدّدة الخطوات.
@transaction التحوّلات يفرض تشغيل عملية تغيير دائمًا في عملية قاعدة بيانات. اطّلِع على العمليات المتعدّدة الخطوات.

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

قد يهمّك الاطّلاع على ما يلي: