ActiveRecord לעומת אקטו חלק שני

זהו החלק השני בסדרת "ActiveRecord vs. Ecto", שבה באטמן ובתגירל נלחמים על מסדי נתונים שאילתות ואנחנו משווים תפוחים ותפוזים.

לאחר בחינת סכמות מסדי נתונים והעברות ב- ActiveRecord לעומת Ecto חלק ראשון, פוסט זה מכסה כיצד ActiveRecord ו- Ecto מאפשרים למפתחים לבצע שאילתות במסד הנתונים, וכיצד גם ActiveRecord וגם Ecto משתווים כאשר מתמודדים עם אותן דרישות. במהלך הדרך נגלה גם את זהותה של באטגירל 1989–2011.

נתוני זרעים

בואו נתחיל! בהתבסס על מבנה בסיס הנתונים שהוגדר בפוסט הראשון בסדרה זו, נניח שהמשתמשים וטבלאות החשבוניות מאוחסנים בהם הנתונים הבאים:

משתמשים

* שדה ה- create_at של ActiveRecord נקרא insert_at באקטו כברירת מחדל.

חשבוניות

* שדה ה- create_at של ActiveRecord נקרא insert_at באקטו כברירת מחדל.

שאילתות המתבצעות באמצעות פוסט זה מניחות כי הנתונים שלמעלה מאוחסנים בבסיס הנתונים, לכן יש לזכור מידע זה במהלך הקריאה.

מצא פריט באמצעות המפתח הראשי שלו

נתחיל עם קבלת רשומה ממסד הנתונים באמצעות המפתח הראשי שלה.

ActiveRecord

irb (main): 001: 0> User.find (1) טעינת משתמש (0.4ms) בחר "משתמשים". * מ- "משתמשים" איפה "משתמשים". "id" = $ 1 הגבלה $ 2 [["id", 1 ], ["LIMIT", 1]] => # <מזהה משתמש: 1, שם מלא: "Bette Kane", דוא"ל: "bette@kane.test", create_at: "2018-01-01 10:01:00" , updated_at: "2018-01-01 10:01:00">

אקטו

iex (3)> Repo.get (משתמש, 1)
[debug] QUERY אישור מקור = "משתמשים" db = 5.2ms מפענח = 2.5ms תור = 0.1ms
בחר u0. "Id", u0. "Full_name", u0. "Email", u0. "Insert_at", u0. "Updated_at" מ- "משתמשים" AS u0 WHERE (u0. "Id" = $ 1) [1]
% Financex.Accounts.User {
  __meta__: # Ecto.Schema.Metadata <: טעון, "משתמשים">,
  דוא"ל: "bette@kane.test",
  שם מלא: "בט קיין",
  id: 1,
  insert_at: ~ N [2018-01-01 10: 01: 00.000000],
  חשבוניות: # Ecto.Association.NotLoaded ,
  updated_at: ~ N [2018-01-01 10: 01: 00.000000]
}

השוואה

שני המקרים דומים למדי. ActiveRecord מסתמך על שיטת מציאת המחלקה של כיתת מודל המשתמש. המשמעות היא שלכל כיתת ActiveRecord ילדים יש שיטת מציאה משלה.

אקטו משתמש בגישה שונה, תוך הסתמכות על מושג המאגר כמתווך בין שכבת המיפוי לתחום. בעת השימוש ב- Ecto, למודול המשתמש אין ידע כיצד למצוא את עצמו. אחריות כזו קיימת במודול ה- Repo, שמסוגל למפות אותה לחנות הנתונים הנמצאת מתחת לנתונים, שבמקרה שלנו היא Postgres.

כשמשווים את שאילתת SQL עצמה, אנו יכולים לאתר כמה הבדלים:

  • ActiveRecord טוען את כל השדות (משתמשים. *), ואילו Ecto טוען רק את השדות הרשומים בהגדרת הסכימה.
  • ActiveRecord כולל LIMIT 1 לשאילתה, ואילו Ecto לא עושה זאת.

שולף את כל הפריטים

בואו נלך צעד קדימה ונטען את כל המשתמשים מהמאגר.

ActiveRecord

irb (main): 001: 0> User.all טעינת משתמשים (0.5ms) בחר "משתמשים". * מ- "משתמשים" LIMIT $ 1 [["LIMIT", 11]] => # , # <מזהה משתמש: 2, מלא_שם:" ברברה גורדון ", דוא"ל:" barbara@gordon.test ", create_at:" 2018-01-02 10:02:00 ", updated_at:" 2018-01-02 10:02:00 ">, # <מזהה משתמש: 3, שם מלא:" קסנדרה קין ", דוא"ל:" cassandra@cain.test ", נוצר_מת:" 2018-01-03 10:03:00 ", מעודכן ב:" 2018-01-03 10:03:00 ">, # <מזהה משתמש: 4, שם מלא:" סטפני בראון ", דוא"ל:" stephanie@brown.test ", נוצר_ב:" 2018-01-04 10:04:00 ", updated_at:" 2018-01-04 10:04:00 ">]>

אקטו

iex (4)> Repo.all (משתמש)
[debug] QUERY אישור מקור = "משתמשים" db = 2.8ms מפענח = 0.2ms תור = 0.2ms
בחר u0. "Id", u0. "Full_name", u0. "דואר אלקטרוני", u0. "Insert_at", u0. "מעודכן_ב"המשתמשים" AS u0 []
[
  % Financex.Accounts.User {
    __meta__: # Ecto.Schema.Metadata <: טעון, "משתמשים">,
    דוא"ל: "bette@kane.test",
    שם מלא: "בט קיין",
    id: 1,
    insert_at: ~ N [2018-01-01 10: 01: 00.000000],
    חשבוניות: # Ecto.Association.NotLoaded ,
    updated_at: ~ N [2018-01-01 10: 01: 00.000000]
  },
  % Financex.Accounts.User {
    __meta__: # Ecto.Schema.Metadata <: טעון, "משתמשים">,
    דוא"ל: "barbara@gordon.test",
    שם מלא: "ברברה גורדון",
    id: 2,
    insert_at: ~ N [2018-01-02 10: 02: 00.000000],
    חשבוניות: # Ecto.Association.NotLoaded ,
    updated_at: ~ N [2018-01-02 10: 02: 00.000000]
  },
  % Financex.Accounts.User {
    __meta__: # Ecto.Schema.Metadata <: טעון, "משתמשים">,
    אימייל: "cassandra@cain.test",
    שם מלא: "קסנדרה קיין",
    id: 3,
    insert_at: ~ N [2018-01-03 10: 03: 00.000000],
    חשבוניות: # Ecto.Association.NotLoaded ,
    updated_at: ~ N [2018-01-03 10: 03: 00.000000]
  },
  % Financex.Accounts.User {
    __meta__: # Ecto.Schema.Metadata <: טעון, "משתמשים">,
    דוא"ל: "stephanie@brown.test",
    שם מלא: "סטפני בראון",
    id: 4,
    insert_at: ~ N [2018-01-04 10: 04: 00.000000],
    חשבוניות: # Ecto.Association.NotLoaded ,
    updated_at: ~ N [2018-01-04 10: 04: 00.000000]
  }
]

השוואה

זה לפי אותה תבנית בדיוק כמו החלק הקודם. ActiveRecord משתמש בשיטת כל הכיתה ו- Ecto מסתמך על תבנית המאגר כדי לטעון את הרשומות.

יש שוב כמה הבדלים בשאלות SQL:

שאילתות עם תנאים

לא סביר מאוד שאנחנו צריכים להביא את כל הרשומות מהטבלה. צורך נפוץ הוא שימוש בתנאים, לסינון הנתונים שהוחזרו.

בואו נשתמש בדוגמה זו כדי לרשום את כל החשבוניות שעדיין יש לשלם (היכן ששולמו_אין אפס).

ActiveRecord

irb (main): 024: 0> Invoice.where (paid_at: nil) טעינת חשבוניות (18.2ms) בחר "חשבוניות". * מ- "חשבוניות" איפה "חשבוניות". "paid_at" הוא הגבלה אפסית של $ 1 [["הגבלה" , 11]] => # , # <מזהה חשבונית: 4, user_id: 4, Payment_method: nil, paid_at: nil, create_at:" 2018-01-05 08:00:00 ", updated_at:" 2018-01-05 08:00:00 ">]>

אקטו

iex (19)> איפה (חשבונית, [i], is_nil (i.paid_at)) |> Repo.all ()
[debug] QUERY אישור מקור = "חשבוניות" db = 20.2ms
בחר i0. "Id", i0. "Payment_method", i0. "Paid_at", i0. "User_id", i0. "Insert_at", i0. "מעודכן_ב"דרך" חשבוניות "AS i0 איפה ריק) []
[
  % כספים. חשבונות. חשבונית {
    __meta__: # Ecto.Schema.Metadata <: טעון, "חשבוניות">,
    id: 3,
    insert_at: ~ N [2018-01-04 08: 00: 00.000000],
    שילם_ט: אפסי,
    Payment_method: אפסי,
    updated_at: ~ N [2018-01-04 08: 00: 00.000000],
    user: # Ecto.Association.NotLoaded ,
    user_id: 3
  },
  % כספים. חשבונות. חשבונית {
    __meta__: # Ecto.Schema.Metadata <: טעון, "חשבוניות">,
    id: 4,
    insert_at: ~ N [2018-01-04 08: 00: 00.000000],
    שילם_ט: אפסי,
    Payment_method: אפסי,
    updated_at: ~ N [2018-01-04 08: 00: 00.000000],
    user: # Ecto.Association.NotLoaded ,
    user_id: 4
  }
]

השוואה

בשתי הדוגמאות, שם מילת המפתח משמשת, שהיא חיבור לסעיף SQL WHERE. למרות ששאילתות SQL שנוצרו דומות למדי, אך הדרך בה שני הכלים מגיעים לשם יש כמה הבדלים חשובים.

ActiveRecord הופך את הארגומנט betalte_at: nil להצהרת pays_at IS NULL SQL אוטומטית. על מנת להגיע לאותה פלט באמצעות Ecto, מפתחים צריכים להיות מפורשים יותר לגבי כוונתם, על ידי קוראים ל- is_nil ().

הבדל נוסף שיש להדגיש הוא ההתנהגות ה"טהורה "של הפונקציה באקטו. כשאתה מתקשר לפונקציית היכן בלבד, הוא אינו מתקשר עם מסד הנתונים. החזרת הפונקציה היכן היא מבנה Ecto.Query:

iex (20)> איפה (חשבונית, [i], is_nil (i.paid_at))
# Ecto.Query <מ- i ב- Financex.Accounts.vovo, איפה: is_nil (i.paid_at)>

בסיס הנתונים נוגע רק כאשר נקראת הפונקציה Repo.all () ומעבירה את struct Ecto.Query כארגומנט. גישה זו מאפשרת הרכב שאילתות ב- Ecto, נשוא החלק הבא.

הרכב שאילתה

אחד ההיבטים החזקים ביותר בשאילתות בסיסי נתונים הוא ההרכב. הוא מתאר שאילתה באופן שמכיל יותר ממצב יחיד.

אם אתה בונה שאילתות SQL גולמיות, פירוש הדבר שסביר להניח שתשתמש באיזה שרשור. דמיין שיש לך שני תנאים:

  1. not_paid = 'שילם_אין אפס'
  2. pays_with_paypal = 'payment_method = "Paypal"'

כדי לשלב את שני התנאים הללו באמצעות SQL גולמי, פירושו שתצטרך לשרשר אותם באמצעות משהו דומה ל:

בחר * מתוך חשבוניות איפה # {לא_ בתשלום} ו- # {בתשלום_ עם_ PayPal}

למרבה המזל גם ל- ActiveRecord וגם לאקטו יש פיתרון לזה.

ActiveRecord

irb (main): 003: 0> Invoice.where.not (paid_at: nil). Where (Payment_method: "Paypal") טעינת חשבוניות (8.0ms) בחר "חשבוניות". * מ- "חשבוניות" איפה "חשבוניות". " paid_at "אינן NULL ו-" חשבוניות "." Payment_method "= $ 1 הגבלה $ 2 [[" Payment_method "," Paypal "], [" LIMIT ", 11]] => # ]>

אקטו

iex (6)> חשבונית |> איפה ([i], לא is_nil (i.paid_at)) |> איפה ([i], i.payment_method == "Paypal") |> Repo.all ()
[debug] QUERY אישור מקור = "חשבוניות" db = 30.0ms מפענח = 0.6ms תור = 0.2ms
בחר i0. "Id", i0. "Payment_method", i0. "Paid_at", i0. "User_id", i0. "Insert_at", i0. "מעודכן_ב"דרך" חשבוניות "AS i0 איפה (לא (i0." שילם_ט "IS NULL)) AND (i0." Payment_method "= 'Paypal') []
[
  % כספים. חשבונות. חשבונית {
    __meta__: # Ecto.Schema.Metadata <: טעון, "חשבוניות">,
    id: 2,
    insert_at: ~ N [2018-01-03 08: 00: 00.000000],
    pays_at: #DateTime <2018-02-01 08: 00: 00.000000Z>,
    payment_method: "Paypal",
    updated_at: ~ N [2018-01-03 08: 00: 00.000000],
    user: # Ecto.Association.NotLoaded ,
    user_id: 2
  }
]

השוואה

שתי השאלות עונות על אותה שאלה: "אילו חשבוניות שולמו והשתמשו ב- Paypal?".

כצפוי, ActiveRecord מציע דרך תמציתית יותר לחבר את השאילתה (למשל), בעוד Ecto דורשת ממפתחים להשקיע קצת יותר בכתיבת השאילתה. כרגיל, בתג'ירל (היתומה, אילמת כזו עם זהות קסנדרה קין) או אקטיב-אקורד אינם כה מילוליים.

אל תשתולל על ידי המילה והמורכבות לכאורה של שאילתת האקטו המוצגת לעיל. בסביבה של עולם אמיתי, השאילתה הזו תוחלף כך שתיראה יותר:

חשבונית
|> איפה ([i], לא is_nil (i.paid_at))
|> איפה ([i], i.payment_method == "Paypal")
|> Repo.all ()

מנקודת מבט זו, השילוב של ההיבטים ה"טהורים "של הפונקציה שם, שאינו מבצע פעולות בסיס נתונים בפני עצמו, עם מפעיל הצינורות, הופך את הרכב השאילתות באקטו לנקי באמת.

מזמין

הזמנה היא היבט חשוב בשאילתה. זה מאפשר למפתחים להבטיח שתוצאת שאילתה נתונה עוקבת אחר סדר מוגדר.

ActiveRecord

irb (main): 002: 0> Invoice.order (create_at:: desc) טעינת חשבוניות (1.5ms) בחר "חשבוניות". * מ- "חשבוניות" הזמנה לפי "חשבוניות". "created_at" DESC LIMIT $ 1 [["הגבלה ", 11]] => # , # <מזהה חשבונית: 3, user_id: 3, Payment_method: nil, paid_at: nil, create_at: "2018-01-04 08:00:00", updated_at: "2018-01-04 08:00:00">, # <מזהה חשבונית: 2, user_id: 2, Payment_method: "Paypal", paid_at: "2018-02-01 08:00:00", create_at: "2018 -01-03 08:00:00 ", updated_at:" 2018-01-03 08:00:00 ">, # <מזהה חשבונית: 1, user_id: 1, payment_method:" כרטיס אשראי ", paid_at:" 2018- 02-01 08:00:00 ", create_at:" 2018-01-02 08:00:00 ", updated_at:" 2018-01-02 08:00:00 ">]>

אקטו

iex (6)> order_by (חשבונית, desc:: insert_at) |> Repo.all ()
[debug] QUERY אישור מקור = "חשבוניות" db = 19.8ms
בחר i0. "Id", i0. "Payment_method", i0. "Paid_at", i0. "User_id", i0. "Insert_at", i0. "מעודכן_ב"דרך" חשבוניות "AS i0 להזמין על ידי i0." Insert_at "DESC []
[
  % כספים. חשבונות. חשבונית {
    __meta__: # Ecto.Schema.Metadata <: טעון, "חשבוניות">,
    id: 3,
    insert_at: ~ N [2018-01-04 08: 00: 00.000000],
    שילם_ט: אפסי,
    Payment_method: אפסי,
    updated_at: ~ N [2018-01-04 08: 00: 00.000000],
    user: # Ecto.Association.NotLoaded ,
    user_id: 3
  },
  % כספים. חשבונות. חשבונית {
    __meta__: # Ecto.Schema.Metadata <: טעון, "חשבוניות">,
    id: 4,
    insert_at: ~ N [2018-01-04 08: 00: 00.000000],
    שילם_ט: אפסי,
    Payment_method: אפסי,
    updated_at: ~ N [2018-01-04 08: 00: 00.000000],
    user: # Ecto.Association.NotLoaded ,
    user_id: 4
  },
  % כספים. חשבונות. חשבונית {
    __meta__: # Ecto.Schema.Metadata <: טעון, "חשבוניות">,
    id: 2,
    insert_at: ~ N [2018-01-03 08: 00: 00.000000],
    pays_at: #DateTime <2018-02-01 08: 00: 00.000000Z>,
    payment_method: "Paypal",
    updated_at: ~ N [2018-01-03 08: 00: 00.000000],
    user: # Ecto.Association.NotLoaded ,
    user_id: 2
  },
  % כספים. חשבונות. חשבונית {
    __meta__: # Ecto.Schema.Metadata <: טעון, "חשבוניות">,
    id: 1,
    insert_at: ~ N [2018-01-02 08: 00: 00.000000],
    pays_at: #DateTime <2018-02-01 08: 00: 00.000000Z>,
    payment_method: "כרטיס אשראי",
    updated_at: ~ N [2018-01-02 08: 00: 00.000000],
    user: # Ecto.Association.NotLoaded ,
    user_id: 1
  }
]

השוואה

הוספת הזמנה לשאילתה הינה ישר קדימה בשני הכלים.

למרות שהדוגמה של Ecto משתמשת בחשבונית כפרמטר הראשון, הפונקציה order_by מקבלת גם מבנים של Ecto.Query, המאפשרת להשתמש בפונקציית order_by בהרכבים, כמו:

חשבונית
|> איפה ([i], לא is_nil (i.paid_at))
|> איפה ([i], i.payment_method == "Paypal")
|> order_by (desc:: insert_at)
|> Repo.all ()

מגביל

מה יהיה מסד נתונים ללא הגבלה? אסון. למרבה המזל, גם ActiveRecord וגם Ecto עוזרים להגביל את מספר הרשומות שהוחזרו.

ActiveRecord

irb (main): 004: 0> Invoice.limit (2)
טעינת חשבוניות (0.2ms) בחר "חשבוניות". * מ- "חשבוניות" LIMIT $ 1 [["LIMIT", 2]]
=> # , # <מזהה חשבונית: 2, user_id: 2, Payment_method:" Paypal ", paid_at:" 2018-02-01 08: 00:00 ", create_at:" 2018-01-03 08:00:00 ", updated_at:" 2018-01-03 08:00:00 ">]>

אקטו

iex (22)> גבול (חשבונית, 2) |> Repo.all ()
[debug] QUERY אישור מקור = "חשבוניות" db = 3.6ms
בחר i0. "Id", i0. "Payment_method", i0. "Paid_at", i0. "User_id", i0. "Insert_at", i0. "מעודכן_ב"דרך" חשבוניות "AS i0 LIMIT 2 []
[
  % כספים. חשבונות. חשבונית {
    __meta__: # Ecto.Schema.Metadata <: טעון, "חשבוניות">,
    id: 1,
    insert_at: ~ N [2018-01-02 08: 00: 00.000000],
    pays_at: #DateTime <2018-02-01 08: 00: 00.000000Z>,
    payment_method: "כרטיס אשראי",
    updated_at: ~ N [2018-01-02 08: 00: 00.000000],
    user: # Ecto.Association.NotLoaded ,
    user_id: 1
  },
  % כספים. חשבונות. חשבונית {
    __meta__: # Ecto.Schema.Metadata <: טעון, "חשבוניות">,
    id: 2,
    insert_at: ~ N [2018-01-03 08: 00: 00.000000],
    pays_at: #DateTime <2018-02-01 08: 00: 00.000000Z>,
    payment_method: "Paypal",
    updated_at: ~ N [2018-01-03 08: 00: 00.000000],
    user: # Ecto.Association.NotLoaded ,
    user_id: 2
  }
]

השוואה

הן ל- ActiveRecord והן לאקטו יש דרך להגביל את מספר הרשומות שהוחזרו על ידי שאילתה.

המגבלה של אקטו פועלת באופן דומה לסדר_בי, והיא מתאימה ליצירות שאילתה.

עמותות

ל- ActiveRecord ו- Ecto יש גישות שונות בכל הנוגע לאופן הטיפול באסוציאציות.

ActiveRecord

ב- ActiveRecord, אתה יכול להשתמש בכל אסוציאציה שהוגדרה במודל, מבלי שתצטרך לעשות משהו מיוחד בנושא, לדוגמה:

irb (main): 012: 0> user = User.find (2) טעינת משתמש (0.3ms) בחר "משתמשים". * מ- "משתמשים" איפה "משתמשים". "id" = $ 1 הגבלה $ 2 [["id" , 2], ["LIMIT", 1]] => # <מזהה משתמש: 2, שם מלא: "ברברה גורדון", דוא"ל: "barbara@gordon.test", create_at: "2018-01-02 10:02: 00 ", updated_at:" 2018-01-02 10:02:00 "> irb (main): 013: 0> user.invoices טעינת חשבוניות (0.4ms) בחר" חשבוניות ". * מ-" חשבוניות "איפה" חשבוניות " . "user_id" = $ 1 LIMIT $ 2 [["user_id", 2], ["LIMIT", 11]] => # ] >

הדוגמה שלמעלה מראה שאנו יכולים לקבל רשימה של חשבוניות המשתמש כאשר מתקשרים לחשבוניות user.in. כשעשה זאת, ActiveRecord השאיל באופן אוטומטי את מסד הנתונים והעמיס את החשבוניות המשויכות למשתמש. אמנם גישה זו מקלה על הדברים, במובן של כתיבת פחות קוד או צורך לדאוג מצעדים נוספים, יתכן שזו בעיה אם אתה חוזר על מספר משתמשים ומביא את החשבוניות עבור כל משתמש. בעיה זו ידועה כ"בעיית N + 1 ".

ב- ActiveRecord, התיקון המוצע לבעיית "N + 1" הוא להשתמש בשיטה הכוללת:

irb (main): 022: 0> user = User.includes (: חשבוניות) .find (2) עומס משתמש (0.3ms) בחר "משתמשים". * מ- "משתמשים" איפה "משתמשים". "id" = $ 1 הגבלה $ 2 [["id", 2], ["LIMIT", 1]] טעינת חשבוניות (0.6ms) בחר "חשבוניות". * מ- "חשבוניות" איפה "חשבוניות". "User_id" = $ 1 [["user_id", 2]] => # <מזהה משתמש: 2, שם מלא: "ברברה גורדון", דוא"ל: "barbara@gordon.test", create_at: "2018-01-02 10:02:00", updated_at: "2018-01 -02 10:02:00 "> irb (main): 023: 0> user.invoices => # ]>

במקרה זה, ActiveRecord טעון לטעון את שיוך החשבוניות בעת הבאת המשתמש (כפי שניתן לראות בשתי שאילתות SQL המוצגות).

אקטו

כפי שאולי כבר שמתם לב, אקטו ממש לא אוהבת קסם או השלכה. זה דורש מהמפתחים להיות מפורשים לגבי כוונתם.

בואו לנסות את אותה גישה של שימוש בחשבוניות user.cure עם Ecto:

iex (7)> ​​משתמש = Repo.get (משתמש, 2)
[debug] QUERY אישור מקור = "משתמשים" db = 18.3ms מפענח = 0.6ms
בחר u0. "Id", u0. "Full_name", u0. "Email", u0. "Insert_at", u0. "Updated_at" מ- "משתמשים" AS u0 WHERE (u0. "Id" = $ 1) [2]
% Financex.Accounts.User {
  __meta__: # Ecto.Schema.Metadata <: טעון, "משתמשים">,
  דוא"ל: "barbara@gordon.test",
  שם מלא: "ברברה גורדון",
  id: 2,
  insert_at: ~ N [2018-01-02 10: 02: 00.000000],
  חשבוניות: # Ecto.Association.NotLoaded ,
  updated_at: ~ N [2018-01-02 10: 02: 00.000000]
}
iex (8)> חשבוניות user.info
# Ecto.Association.NotLoaded 

התוצאה היא Ecto.Association.NotLoaded. לא כל כך שימושי.

כדי לקבל גישה לחשבוניות, מפתח צריך ליידע את חברת Ecto על כך, באמצעות פונקציית הטעינה מראש:

iex (12)> משתמש = טעינה מוקדמת (משתמש: חשבוניות) |> Repo.get (2)
[debug] QUERY אישור מקור = "משתמשים" db = 11.8ms
בחר u0. "Id", u0. "Full_name", u0. "Email", u0. "Insert_at", u0. "Updated_at" מ- "משתמשים" AS u0 WHERE (u0. "Id" = $ 1) [2]
[debug] QUERY אישור מקור = "חשבוניות" db = 4.2ms
בחר i0. "Id", i0. "Payment_method", i0. "Paid_at", i0. "User_id", i0. "Insert_at", i0. "Updated_at", i0. "User_id" FRA "חשבוניות" AS i0 WHERE ( i0. "user_id" = $ 1) הזמנה מאת i0. "user_id" [2]
% Financex.Accounts.User {
  __meta__: # Ecto.Schema.Metadata <: טעון, "משתמשים">,
  דוא"ל: "barbara@gordon.test",
  שם מלא: "ברברה גורדון",
  id: 2,
  insert_at: ~ N [2018-01-02 10: 02: 00.000000],
  חשבוניות: [
    % כספים. חשבונות. חשבונית {
      __meta__: # Ecto.Schema.Metadata <: טעון, "חשבוניות">,
      id: 2,
      insert_at: ~ N [2018-01-03 08: 00: 00.000000],
      pays_at: #DateTime <2018-02-01 08: 00: 00.000000Z>,
      payment_method: "Paypal",
      updated_at: ~ N [2018-01-03 08: 00: 00.000000],
      user: # Ecto.Association.NotLoaded ,
      user_id: 2
    }
  ],
  updated_at: ~ N [2018-01-02 10: 02: 00.000000]
}

iex (15)> חשבוניות user.info
[
  % כספים. חשבונות. חשבונית {
    __meta__: # Ecto.Schema.Metadata <: טעון, "חשבוניות">,
    id: 2,
    insert_at: ~ N [2018-01-03 08: 00: 00.000000],
    pays_at: #DateTime <2018-02-01 08: 00: 00.000000Z>,
    payment_method: "Paypal",
    updated_at: ~ N [2018-01-03 08: 00: 00.000000],
    user: # Ecto.Association.NotLoaded ,
    user_id: 2
  }
]

בדומה ל- ActiveRecord כולל, הטעינה מראש עם אחיזת החשבוניות המשויכות, אשר תהפוך אותם לזמינים כאשר מתקשרים לחשבוניות user.in.

השוואה

שוב, הקרב בין ActiveRecord לאקטו מסתיים בנקודה ידועה: עדות. שני הכלים מאפשרים למפתחים לגשת לאסוציאציות בקלות, אך בעוד ש- ActiveRecord הופך אותה למילולית פחות, התוצאה עשויה להיות בעלת התנהגויות בלתי צפויות. Ecto עוקב אחר הגישה מסוג WYSIWYG, שרק עושה את מה שרואים בשאילתה שהוגדרה על ידי היזם.

Rails ידועה בשימוש וקידום אסטרטגיות מטמון בכל השכבות השונות של היישום. דוגמא אחת היא השימוש בגישת המטמון "בובה רוסית", הנשענת כולה על "N + 1" עבור מנגנון המטמון שלה לביצוע קסמו.

אימות

רוב האימות שקיים ב- ActiveRecord זמין גם ב- Ecto. להלן רשימת תוקפים נפוצים וכיצד הן ActiveRecord והן Ecto מגדירים אותם:

לעטוף

הנה לך את זה: התפוחים החיוניים לעומת השוואת התפוזים.

ActiveRecord מתמקד בקלות ביצוע שאילתות בסיסי נתונים. הרוב הגדול של תכונותיו מרוכזות בשיעורי הדגמים עצמם, ואינן מחייבות למפתחים הבנה מעמיקה של מסד הנתונים, וגם לא מההשפעה של פעולות כאלה. ActiveRecord עושה הרבה דברים ברמיזה כברירת מחדל. למרות שזה מקל על ההתחלה, זה מקשה על הבנת המתרחש מאחורי הקלעים וזה עובד רק אם אתה פועל לפי "ActiveRecord דרך".

לעומת זאת, אקטו דורש עדויות המובילות בקוד מילולי יותר. כיתרון, הכל נמצא באור הזרקורים, שום דבר מאחורי הקלעים ותוכלו לציין את הדרך האישית שלכם.

לשניהם יש את החלק הפנימי שלהם בהתאם לפרספקטיבה שלך והעדפתך. אז בהשוואה בין תפוחים ותפוזים, אנו מגיעים לסוף ה- BAT-tle הזה. כמעט שכחתי להגיד לך שמך הקוד של באטגירל (1989–2001) היה ... אורקל. אבל בוא לא ניכנס לזה.

פוסט זה נכתב על ידי סופר אורח אלביו ויקוסה. אלוויו הוא מחבר הספר הפניקס למפתחי מסילות.

פורסם במקור ב blog.appsignal.com ב- 9 באוקטובר 2018.