בגרות במדעי המחשב תכנות באינטרנט 899282/899372 - קיץ 2023
נבחנים אקסטרניים · שאלון 899282/899372 · 9 שאלות · 2 שעות · פתרון מלא לכל סעיף
בחינת הבגרות במדעי המחשב, תכנות באינטרנט, קיץ 2023, כל 9 השאלות כמו בשאלון. לכל סעיף יש תשובה ופתרון מלא: הרעיון, הקוד או המעקב, ובדיקה קצרה. כל קוד מופיע ב-Java וב-C#. נסו לפתור לבד, ואז פתחו את הפתרון.
הוראות הבחינה (כמו בשאלון)
א. משך הבחינה: שעתיים.
ב. מבנה השאלון ומפתח הערכה:
פרק ראשון (10*3) 30 נקודות
פרק שני (20*2) + (10*1) 50 נקודות
פרק שלישי (20*1) 20 נקודות
סך הכל 100 נקודות
ג. חומר עזר מותר בשימוש: כל חומר עזר, חוץ ממחשבון שיש בו אפשרות תכנות.
כתבו במחברת הבחינה בלבד, רישמו "טיוטה" בראש כל עמוד המשמש טיוטה.
כתיבת טיוטה בדפים שאינם במחברת הבחינה עלולה לגרום לפסילת הבחינה.
השאלות בשאלון זה מנוסחות בלשון רבים, אף על פי כן על כל תלמידה וכל תלמיד להשיב עליהן באופן אישי.
בהצלחה!
פרק ראשון (30 נקודות)
ענו על שלוש השאלות 1-3 (לכל שאלה – 10 נקודות)
שאלה 1 · תפקיד Session
מקובל להשתמש במונח Session בתכנות בסביבת אינטרנט. מה תפקידו של Session?
העתיקו למחברת הבחינה את התשובה הנכונה מבין האפשרויות א–ד שלפניכם.
א. אובייקט השומר מידע עבור האתר עצמו.
ב. העברת מידע מן הטופס לשרת בצורה גלויה.
ג. אובייקט השומר מידע עבור משתמש מסויים.
ד. רכיב המאפשר למחשבים להתחבר לרשת האינטרנט.
העתיקו למחברת הבחינה את התשובה הנכונה מבין האפשרויות א–ד.
◂ פתרון מלא לשאלה 1
פתרון
ג. אובייקט השומר מידע עבור משתמש מסויים.
מה נדרש – לבחור את ההגדרה הנכונה של Session.
רעיון – בשרת ASP.NET יש שני אובייקטים לשמירת מידע בין דפים ובין בקשות:
Session["..."] של משתמש אחד אינו נראה למשתמש אחר. לדוגמה: שם המשתמש שהתחבר, סל קניות.פתרון – נעבור על האפשרויות:
תשובה: ג.
בדיקה – בשאלה 5 באותו שאלון שומרים ב־Session["name"], Session["age"] נתונים של המשתמש הנוכחי – בדיוק השימוש באפשרות ג.
טעות נפוצה: לבלבל בין Session (לכל משתמש) לבין Application (לכל האתר) ולבחור באפשרות א.
שאלה 2 · שאילתת SQL – טבלת משחקים
במסד נתונים של משחקי כדורגל מוגדרת טבלה בשם Games ובה נתוני תוצאות משחקי העונה. בטבלה יש שש עמודות:
א. שם קבוצה (name).
ב. כמות משחקים (num).
ג. כמות נצחונות (win).
ד. כמות הפסדים (lost).
ה. כמות תוצאות תיקו (tie).
ו. ניקוד כולל (score).
כתבו שאילתה בשפת SQL המאחזרת את שמות הקבוצות בהן כמות הניצחונות גדולה או שווה לכמות ההפסדים.
◂ פתרון מלא לשאלה 2
פתרון
SELECT name FROM Games WHERE win >= lost;
מה נדרש – שאילתה שמחזירה רק את עמודת שם הקבוצה, עבור השורות שבהן win ≥ lost.
רעיון – בוחרים (SELECT) רק את העמודה name, מהטבלה (FROM) Games, ומסננים שורות בתנאי (WHERE) שמשווה בין שתי עמודות באותה שורה: win >= lost.
פתרון
SELECT name
FROM Games
WHERE win >= lost;בדיקה – השאילתה על טבלה קטנה לדוגמה:
| name | num | win | lost | tie | score |
|---|---|---|---|---|---|
| מכבי | 10 | 6 | 2 | 2 | 20 |
| הפועל | 10 | 3 | 5 | 2 | 11 |
| בית"ר | 10 | 4 | 4 | 2 | 14 |
| בני | 10 | 1 | 7 | 2 | 5 |
התוצאה: מכבי (6 ≥ 2) ו־בית"ר (4 ≥ 4, שוויון נכלל). הפועל ובני לא הוחזרו כי אצלן win < lost.
טעות נפוצה: לכתוב > במקום >= – אז קבוצה עם מספר ניצחונות שווה למספר ההפסדים (כמו בית"ר) לא תוחזר, והשאלה דורשת "גדולה או שווה".
שאלה 3 · פלט של פונקציה בצד השרת (Response.Write)
לפניכם פונקציה בשם Func הכתובה בצד השרת. העתק למחברתך את מה שיוצג בדפדפן לאחר הרצת הפונקציה Func עם הפרמטר num = 21.
public void Func (int num) {
string str = "<table border = '1'>";
int i = 2;
while (i < num) {
if (num % i ==0)
str += "<tr><td>" + i + "</td></tr>";
i++;
}
str += "</table>";
Response.Write (str);
}העתק למחברתך את מה שיוצג בדפדפן לאחר הרצת הפונקציה Func עם הפרמטר num = 21.
◂ פתרון מלא לשאלה 3
פתרון
טבלה עם מסגרת, בעלת עמודה אחת ושתי שורות: בשורה הראשונה 3 ובשורה השנייה 7.
(ה־HTML שנשלח: <table border = '1'><tr><td>3</td></tr><tr><td>7</td></tr></table>)
מה נדרש – להבין איזה HTML הפונקציה בונה כש־num = 21, ואיך הדפדפן מציג אותו.
רעיון – הפונקציה בונה מחרוזת HTML של טבלה. הלולאה עוברת על כל i מ־2 עד num−1 (כלומר 2..20), ולכל i שמחלק את num ללא שארית (num % i == 0) מוסיפה שורה <tr> עם תא אחד <td> שבו הערך i. בסוף Response.Write שולח את המחרוזת לדפדפן. כלומר: הטבלה מציגה את המחלקים של num (בלי 1 ובלי num עצמו).
פתרון – מעקב (רק הערכים של i שבהם התנאי מתקיים משנים את str):
| i | 21 % i | מתחלק? | מה נוסף ל־str |
|---|---|---|---|
| 2 | 1 | לא | – |
| 3 | 0 | כן | <tr><td>3</td></tr> |
| 4, 5, 6 | 1, 1, 3 | לא | – |
| 7 | 0 | כן | <tr><td>7</td></tr> |
| 8 … 20 | ≠ 0 | לא | – |
| 21 | – | הלולאה נעצרת (i < num לא מתקיים) | – |
המחרוזת שנשלחת לדפדפן:
<table border = '1'><tr><td>3</td></tr><tr><td>7</td></tr></table>מה יוצג בדפדפן – טבלה עם מסגרת (border = 1), עמודה אחת ושתי שורות:
| 3 |
| 7 |
בדיקה – הפונקציה כפי שהיא מודפסת בשאלון, עם num = 21, מפיקה בדיוק:<table border = '1'><tr><td>3</td></tr><tr><td>7</td></tr></table>.
(לבדיקה נוספת: עם num = 12 מתקבלות השורות 2, 3, 4, 6, ועם num = 13 – מספר ראשוני – מתקבלת טבלה ריקה.)
טעות נפוצה: לכתוב גם את 1 ואת 21 – הלולאה מתחילה מ־2 ונעצרת לפני num. טעות נוספת: להעתיק את קוד ה־HTML במקום לתאר/לצייר את מה שמוצג בדפדפן – השאלה שואלת מה יוצג (טבלה עם המספרים 3 ו־7).
פרק שני (50 נקודות)
ענו על שלוש שאלות:
שאלה 4 (שאלת חובה – 10 נקודות) ועל שתיים מן השאלות 5-7 (לכל שאלה - 20 נקודות)
שאלה 4 · טבלת HTML עם colspan/rowspan וקישור בתמונה (10 נקודות)
נועה, תלמידת מדעי המחשב, פיתחה אתר ובו מידע על ערי בירה באירופה. באתר תיקייה בשם Images ובה תמונה של דגל בשם flag.png
<!DOCTYPE html>
<html lang="he" >
<meta charset="utf-8"/>
<table style="width:150px" border=2px dir="rtl">
<tr >
<td colspan=2>אירופה</td>
</tr>
<tr>
<td rowspan=3>ערי בירה</td>
<td>פריז</td>
</tr>
<tr >
<td >לונדון</td>
</tr>
<tr>
<td>בריסל</td>
</tr>
<tr>
<td colspan="2" align="center">
<img src="Images/flag.png" />
</td>
</tr>
</table>
</html>כיצד יוצג הדף? כיתבו במחברת הבחינה את מספר התשובה הנכונה מבין האפשרויות (a-d).

הוסיפו שורת קוד מתאימה ב html כך שלחיצה על תמונת הדגל תעביר לאתר:
https://en.wikipedia.org/wiki/Europe
◂ פתרון מלא לשאלה 4
סעיף א
b
מה נדרש – לזהות איזה מארבעת הציורים מתאים לטבלה שבקוד.
רעיון – עוברים שורה־שורה (<tr>) ובודקים כמה תאים יש בכל שורה ומה המשמעות של colspan (תא שמתפרש על כמה עמודות) ושל rowspan (תא שמתפרש על כמה שורות). dir="rtl" אומר שהתא הראשון בשורה מופיע מימין.
פתרון
colspan=2 – "אירופה" תופס את כל רוחב הטבלה (שתי עמודות).rowspan=3 – תא אחד גבוה שתופס את שורות 2, 3, 4 בעמודה הימנית (הראשונה, בגלל rtl). לידו משמאל "פריז".colspan="2" עם align="center" – תמונת הדגל במרכז של תא ברוחב כל הטבלה.נפסול את האפשרויות האחרות:
תשובה: b.
בדיקה – בדפדפן מוצגים "אירופה" בשורה מלאה, "ערי בירה" מימין בגובה שלוש שורות, פריז/לונדון/בריסל בעמודה השמאלית, והדגל ממורכז בשורה התחתונה ברוחב מלא – כמו באפשרות b.
טעות נפוצה: לחשוב שבשורות של "לונדון" ו"בריסל" התא היחיד יופיע מימין – אבל המקום הימני תפוס על ידי התא עם rowspan, ולכן הם עוברים לעמודה השמאלית.
סעיף ב
עוטפים את התמונה בתגית קישור:
<a href="https://en.wikipedia.org/wiki/Europe"><img src="Images/flag.png" /></a>
מה נדרש – שלחיצה על תמונת הדגל תעביר לכתובת https://en.wikipedia.org/wiki/Europe.
רעיון – קישור ב־HTML נוצר בתגית <a href="...">. מה שנמצא בין <a> ל־</a> הוא האזור הלחיץ – אפשר לשים שם טקסט וגם תמונה. לכן עוטפים את תגית ה־<img> בתגית <a>.
פתרון – השורה שבתוך התא האחרון הופכת ל:
<a href="https://en.wikipedia.org/wiki/Europe"><img src="Images/flag.png" /></a>הדף המלא אחרי השינוי:
<!DOCTYPE html>
<html lang="he" >
<meta charset="utf-8"/>
<table style="width:150px" border=2px dir="rtl">
<tr >
<td colspan=2>אירופה</td>
</tr>
<tr>
<td rowspan=3>ערי בירה</td>
<td>פריז</td>
</tr>
<tr >
<td >לונדון</td>
</tr>
<tr>
<td>בריסל</td>
</tr>
<tr>
<td colspan="2" align="center">
<a href="https://en.wikipedia.org/wiki/Europe">
<img src="Images/flag.png" />
</a>
</td>
</tr>
</table>
</html>בדיקה – בדף שהוצג בדפדפן, הדגל נשאר במקומו (שורה תחתונה, במרכז), ולחיצה עליו פותחת את הכתובת שב־href.
אפשרות נוספת (פחות מקובלת): להוסיף לתמונה אירוע JavaScript –<img src="Images/flag.png" onclick="location.href='https://en.wikipedia.org/wiki/Europe'" />.
טעות נפוצה: לשים את הכתובת ב־src של התמונה (אז הדפדפן ינסה להציג את דף ויקיפדיה כתמונה), או לסגור את </a> לפני התמונה – אז הקישור ריק והתמונה אינה לחיצה.
שאלה 5 · הפניית משתמש לפי משתני Session
באתר בתי קולנוע "סרט לי" הוגדרו שלושה משתני Session:
כתבו קטע המפנה את המשתמש באתר לדף המתאים לו, על פי הוראות אלו:
א. משתמש מתחת לגיל 13 יועבר לעמוד kids.aspx
ב. משתמש מגיל 13 ומעלה הצופה בסרטי אקשן (action) או קומדיה (comedy) יועבר לעמוד action.aspx
ג. שאר המשתמשים יועברו לעמוד drama.aspx
◂ פתרון מלא לשאלה 5
פתרון
if ((int)Session["age"] < 13) Response.Redirect("kids.aspx");
else if (genre == "action" || genre == "comedy") Response.Redirect("action.aspx");
else Response.Redirect("drama.aspx");
מה נדרש – קטע קוד בצד השרת (C#) שקורא את הגיל ואת סוג הסרט מה־Session ומעביר את המשתמש לאחד משלושה דפים.
רעיון
object, לכן כשקוראים אותם צריך המרה (casting): (int)Session["age"] לגיל, (string)Session["genre"] (או .ToString()) לסוג הסרט.Response.Redirect("שם הדף").Session["name"] לא נחוץ להחלטה.פתרון
int age = (int)Session["age"];
string genre = (string)Session["genre"];
if (age < 13)
{
Response.Redirect("kids.aspx");
}
else if (genre == "action" || genre == "comedy")
{
Response.Redirect("action.aspx");
}
else
{
Response.Redirect("drama.aspx");
}בדיקה – הקטע על כל המקרים:
| age | genre | הדף שהתקבל |
|---|---|---|
| 5 | action | kids.aspx |
| 12 | drama | kids.aspx |
| 12 | comedy | kids.aspx |
| 13 | action | action.aspx |
| 13 | comedy | action.aspx |
| 13 | drama | drama.aspx |
| 40 | comedy | action.aspx |
| 40 | drama | drama.aspx |
הגבול: גיל 13 בדיוק כבר נחשב "מגיל 13 ומעלה" – לכן התנאי הוא age < 13 ולא age <= 13.
טעות נפוצה: להשוות Session["age"] < 13 בלי המרה ל־int (שגיאת הידור – אי אפשר להשוות object למספר), או לבדוק את סוג הסרט לפני הגיל – אז ילד בן 10 שאוהב קומדיה יועבר בטעות ל־action.aspx.
int age = (int)Session["age"];
string genre = (string)Session["genre"];
if (age < 13)
{
Response.Redirect("kids.aspx");
}
else if (genre == "action" || genre == "comedy")
{
Response.Redirect("action.aspx");
}
else
{
Response.Redirect("drama.aspx");
}שאלה 6 · JavaScript – חילוץ סוג האתר מכתובת
כתובת אתר אינטרנט מורכבת מארבעה חלקים:
א. הכיתוב www (prefix)
ב. שם האתר (name)
ג. סוג האתר (type)– gov, co
ד. סיומת (suffix)– il, com
ארבעת החלקים מחוברים באמצעות התו נקודה (.) לדוגמה:
www.education.gov.il
www.ynet.co.il
כתבו בשפת JavaScript פונקציה בשם getType המקבלת מחרוזת המייצגת כתובת אתר אינטרנט תקין (domain) ומחזירה מחרוזת המכילה את סוג האתר (type). לדוגמה:
◂ פתרון מלא לשאלה 6
פתרון
function getType(domain) { var parts = domain.split("."); return parts[2]; }
מה נדרש – פונקציית JavaScript שמקבלת כתובת כמו www.education.gov.il ומחזירה את החלק השלישי – סוג האתר (gov).
רעיון – הכתובת תקינה ותמיד בנויה מ־4 חלקים המופרדים בנקודה: prefix.name.type.suffix. אם מפרקים את המחרוזת לפי התו "." מתקבל מערך של 4 מחרוזות, וסוג האתר הוא האיבר באינדקס 2 (האינדקסים מתחילים מ־0).
פתרון
function getType(domain) {
var parts = domain.split("."); // ["www", name, type, suffix]
return parts[2];
}עבור "www.education.gov.il" הפעולה split(".") מחזירה את המערך ["www", "education", "gov", "il"], והאיבר parts[2] הוא "gov".
פתרון חלופי בלי split – מוצאים את מקומות הנקודות עם indexOf ולוקחים את התת־מחרוזת שבין הנקודה השנייה לשלישית:
function getType(domain) {
var first = domain.indexOf("."); // the dot after www
var second = domain.indexOf(".", first + 1); // the dot after the site name
var third = domain.indexOf(".", second + 1); // the dot before the suffix
return domain.substring(second + 1, third);
}בדיקה – שתי הגרסאות:
getType("www.education.gov.il") → govgetType("www.ynet.co.il") → cowww.abc.org.com → org, www.x.ac.il → ac.טעות נפוצה: לקחת את parts[1] (שם האתר) במקום parts[2], או לחתוך לפי מיקומים קבועים (למשל תמיד מתו 4) – שם האתר באורך משתנה, ולכן חייבים להיעזר בנקודות. ב־substring(start, end) התו שבמקום end אינו נכלל, ולכן מעבירים בדיוק את מקום הנקודה השלישית.
שאלה 7 · SQL – שאילתה עם כמה תנאים (OR)
במסד נתונים של עיר מסוימת יש טבלה ששמה VehicleTable המכילה את נתוני כלי התחבורה בעיר.
העמודות בטבלה הן:
א. name (שם), מסוג טקסט.
ב. wheels (מספר גלגלים), מסוג מספר שלם.
ג. maxSpeed (מהירות בקמ"ש מקסימלית מותרת) מסוג מספר שלם.
ד. day (מספר כלי תחבורה בשעות היום), מסוג מספר שלם.
ה. evening (מספר כלי תחבורה בשעות הערב) מסוג מספר שלם.
דוגמה לטבלה ובה כמה מן פרטי כלי התחבורה בעיר:
| name | wheels | maxSpeed | day | evening |
|---|---|---|---|---|
| קורקינט | 2 | 20 | 20 | 30 |
| אופניים | 2 | 15 | 45 | 10 |
| אופניים חשמליים | 2 | 35 | 95 | 80 |
| מכונית | 2 | 100 | 250 | 100 |
| אוטובוס | 4 | 80 | 87 | 20 |
| משאית | 4 | 60 | 40 | 5 |
כתבו שאילתה אחת בשפת SQL המבקשת להציג את שמות כלי התחבורה המקיימים אחד או יותר מהתנאים הבאים:
א. מספר כלי התחבורה בשעות היום נמוך ממספר כלי התחבורה בשעות הערב.
ב. מספר הרכבים הכולל ביממה (שעות היום וגם שעות הערב) גדול מ – 100.
ג. מהירות מקסימלית בין 30 קמ"ש ל- 75 קמ"ש (כולל).
◂ פתרון מלא לשאלה 7
פתרון
SELECT name FROM VehicleTable WHERE day < evening OR day + evening > 100 OR maxSpeed BETWEEN 30 AND 75;
(על טבלת הדוגמה: קורקינט, אופניים חשמליים, מכונית, אוטובוס, משאית)
מה נדרש – שאילתה אחת שמחזירה את שמות כלי התחבורה שמקיימים לפחות אחד משלושת התנאים.
רעיון – "אחד או יותר מהתנאים" = חיבור התנאים ב־OR. כל תנאי מתורגם לביטוי על עמודות השורה:
day < eveningday + evening (ב־SQL מותר לחשב ביטוי חשבוני בתנאי) – day + evening > 100maxSpeed BETWEEN 30 AND 75 (BETWEEN כולל את שני הקצוות; שקול ל־maxSpeed >= 30 AND maxSpeed <= 75).פתרון
SELECT name
FROM VehicleTable
WHERE day < evening
OR day + evening > 100
OR maxSpeed BETWEEN 30 AND 75;בדיקה – על טבלת הדוגמה. לכל שורה – אילו תנאים מתקיימים:
| name | א: day < evening | ב: day + evening > 100 | ג: 30 ≤ maxSpeed ≤ 75 | מוצג? |
|---|---|---|---|---|
| קורקינט | 20 < 30 ✔ | 50 ✘ | 20 ✘ | כן |
| אופניים | 45 < 10 ✘ | 55 ✘ | 15 ✘ | לא |
| אופניים חשמליים | ✘ | 175 ✔ | 35 ✔ | כן |
| מכונית | ✘ | 350 ✔ | 100 ✘ | כן |
| אוטובוס | ✘ | 107 ✔ | 80 ✘ | כן |
| משאית | ✘ | 45 ✘ | 60 ✔ | כן |
התוצאה: קורקינט, אופניים חשמליים, מכונית, אוטובוס, משאית.
טעות נפוצה: לחבר את התנאים ב־AND (אז נדרשים כל התנאים יחד, ובטבלת הדוגמה לא יוחזר אף כלי), או לכתוב את תנאי ג כ־maxSpeed > 30 AND maxSpeed < 75 – בלי השוויון, למרות שכתוב "(כולל)". אם מערבבים AND בתוך OR – חובה לשים סוגריים: ... OR (maxSpeed >= 30 AND maxSpeed <= 75).
פרק שלישי (20 נקודות)
ענו על אחת מן השאלות 8-9:
שאלה 8 · בדיקת שם משתמש וסיסמה מול מסד הנתונים
בטופס כניסה לאתר כלשהו נדרש המשתמש להכניס שם משתמש וסיסמה לשדות האלה :
<input type="text" name="id" id="id"/>
<input type="password" name="password" id="password" />בבסיס הנתונים של האתר קיימת טבלה בשם users ובה שתי עמודות:
| name | password |
|---|---|
| Moshe | somePassword |
| Dani | secret |
לפניכם קטע קוד חלקי תקין של פעולה בשם LoginFunc הבודק את שם משתמש וסיסמא. בהתאם לנכונות הקלט, יש להפנות את המשתמש לעמוד המתאים על פי החוקים הבאים:
protected void LoginFunc(string connectionString){
SqlConnection connection = new SqlConnection(connectionString);
SqlCommand command = new SqlCommand();
DataSet ds = new DataSet();
command.CommandText = string.Format("Select * From users Where name = '{0}'",
Request.Form["id"]);
command.Connection= connection;
connection.Open();
SqlDataAdapter adapter = new SqlDataAdapter(command);
adapter.Fill(ds);
connection.Close();
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
}יש להשלים את הקוד החסר בסוף הפעולה (מסומן בכוכביות)
◂ פתרון מלא לשאלה 8
פתרון
if (ds.Tables[0].Rows.Count == 0)
{
Response.Redirect("notExists.aspx");
}
else if (ds.Tables[0].Rows[0]["password"].ToString() == Request.Form["password"])
{
Response.Redirect("welcome.aspx");
}
else
{
Response.Redirect("wrongPassword.aspx");
}
מה נדרש – להשלים את סוף הפעולה: אחרי שהשאילתה רצה והתוצאות נמצאות ב־ds, להחליט לאיזה מבין שלושת הדפים להפנות.
רעיון
Select * From users Where name = '...' מחזירה רק את השורות שבהן השם שווה לשם שהוקלד בשדה id. התוצאה נמצאת בטבלה הראשונה של ה־DataSet: ds.Tables[0].ds.Tables[0].Rows.Count == 0) – השם לא קיים → notExists.aspx.ds.Tables[0].Rows[0]["password"], לסיסמה שהמשתמש הקליד בטופס, Request.Form["password"] (השם password הוא ה־name של שדה הסיסמה בטופס).object, ולכן ממירים אותו ל־string עם ToString() לפני ההשוואה.פתרון – הקוד שנכתב במקום הכוכביות:
if (ds.Tables[0].Rows.Count == 0)
{
Response.Redirect("notExists.aspx");
}
else if (ds.Tables[0].Rows[0]["password"].ToString() == Request.Form["password"])
{
Response.Redirect("welcome.aspx");
}
else
{
Response.Redirect("wrongPassword.aspx");
}הפעולה המלאה:
protected void LoginFunc(string connectionString){
SqlConnection connection = new SqlConnection(connectionString);
SqlCommand command = new SqlCommand();
DataSet ds = new DataSet();
command.CommandText = string.Format("Select * From users Where name = '{0}'",
Request.Form["id"]);
command.Connection= connection;
connection.Open();
SqlDataAdapter adapter = new SqlDataAdapter(command);
adapter.Fill(ds);
connection.Close();
// ---- the missing code ----
if (ds.Tables[0].Rows.Count == 0)
{
Response.Redirect("notExists.aspx");
}
else if (ds.Tables[0].Rows[0]["password"].ToString() == Request.Form["password"])
{
Response.Redirect("welcome.aspx");
}
else
{
Response.Redirect("wrongPassword.aspx");
}
}בדיקה – הפעולה המלאה על הטבלה users מהשאלה:
| id | password | הפניה |
|---|---|---|
| Moshe | somePassword | welcome.aspx |
| Dani | secret | welcome.aspx |
| Dani | somePassword | wrongPassword.aspx |
| Moshe | (ריק) | wrongPassword.aspx |
| Yossi | secret | notExists.aspx |
טעות נפוצה: לגשת ל־Rows[0] בלי לבדוק קודם שיש שורות – כשהשם לא קיים זו שגיאת זמן ריצה. טעות נוספת: להשוות Rows[0]["password"] == Request.Form["password"] בלי ToString – זו השוואה בין object למחרוזת, שבודקת זהות של אובייקטים ולא את התוכן, ולכן תחזיר false גם כשהסיסמה נכונה.
הערה: בניית שאילתה משרשור הקלט של המשתמש (string.Format עם Request.Form) חשופה ל־SQL Injection; באתר אמיתי משתמשים בפרמטרים (@name). כאן הקוד הנתון כתוב כך, ואנו רק משלימים אותו.
protected void LoginFunc(string connectionString){
SqlConnection connection = new SqlConnection(connectionString);
SqlCommand command = new SqlCommand();
DataSet ds = new DataSet();
command.CommandText = string.Format("Select * From users Where name = '{0}'",
Request.Form["id"]);
command.Connection= connection;
connection.Open();
SqlDataAdapter adapter = new SqlDataAdapter(command);
adapter.Fill(ds);
connection.Close();
// ---- the missing code ----
if (ds.Tables[0].Rows.Count == 0)
{
Response.Redirect("notExists.aspx");
}
else if (ds.Tables[0].Rows[0]["password"].ToString() == Request.Form["password"])
{
Response.Redirect("welcome.aspx");
}
else
{
Response.Redirect("wrongPassword.aspx");
}
}שאלה 9 · השלמת פעולה המציגה טבלה ממסד הנתונים
שאלה זו מתייחסת לטבלת הנתונים VehicleTable המוצגת בשאלה 7.
נציג העירייה מעוניין להפיק טבלה ובה נתוני כל כלי התחבורה הדו גלגליים (2 גלגלים) עם מהירות מקסימלית הגדולה מ- 22 קמ"ש (לא כולל). הפונקציה מקבלת מחרוזת התחברות למסד הנתונים connectionString, ומציגה בטבלה את כל העמודות של כלי התחבורה המתאימים.
בפונקציה חסרים שמונה ביטויים מסומנים במספרים בין סוגריים עגולים. כתבו במחברת הבחינה את מספרי הביטויים החסרים (1) – (8) , בסדר עולה, וכתבו ליד כל מספר את הביטוי החסר שהוא מייצג.
protected void printTable(string connectionString)
{
string resultStr = "";
DataSet ds = new DataSet();
SqlConnection connection = new SqlConnection(_____(1)______);
SqlCommand cmd = new SqlCommand();
cmd.CommandText = " _____(2)______ FROM [dbo].[VehicleTable] where ____(3)______";
cmd.Connection = connection;
connection.Open();
SqlDataAdapter adapter = new SqlDataAdapter(____(4)___);
adapter.____(5)___ (ds);
connection.Close();
resultStr += "<table dir=rtl><tr><th>name</th> <th>wheels</th>
<th>maxSpeed</th>";
resultStr += "<th>day</th><th> evening </th></tr>";
foreach (_____(6)______)
{
resultStr += "<___(7)______>";
resultStr += "<td>" + dr["name"] + "</td>";
resultStr += "<td>" + dr[“wheels"] + "</td>";
resultStr += "<td>" + dr["maxSpeed"] + "</td>";
resultStr += "<td>" + dr["day"] + "</td>";
resultStr += "<td>" + dr["evening"] + "</td>";
resultStr += "</tr>";
}
resultStr += "</table>";
_____(8)____ (resultStr);
}כתבו במחברת הבחינה את מספרי הביטויים החסרים (1) – (8) , בסדר עולה, וכתבו ליד כל מספר את הביטוי החסר שהוא מייצג.
◂ פתרון מלא לשאלה 9
פתרון
(1) connectionString
(2) SELECT *
(3) wheels = 2 AND maxSpeed > 22
(4) cmd
(5) Fill
(6) DataRow dr in ds.Tables[0].Rows
(7) tr
(8) Response.Write
מה נדרש – להשלים 8 חורים בפעולה שמתחברת למסד, שולפת את כלי התחבורה הדו־גלגליים שמהירותם המקסימלית גדולה מ־22, ומציגה אותם בטבלת HTML.
רעיון – זה התבנית הקבועה של קריאה ממסד נתונים ב־ASP.NET:
חיבור (SqlConnection עם מחרוזת ההתחברות) → פקודה (SqlCommand עם טקסט השאילתה והחיבור) → פתיחת החיבור → SqlDataAdapter שמקבל את הפקודה וממלא (Fill) את ה־DataSet → סגירת החיבור → מעבר על השורות של ds.Tables[0] ובניית HTML → שליחה לדפדפן עם Response.Write.
פתרון
| מספר | הביטוי החסר | הסבר |
|---|---|---|
| (1) | connectionString | מחרוזת ההתחברות שהפעולה קיבלה כפרמטר |
| (2) | SELECT * | "את כל העמודות" – כוכבית |
| (3) | wheels = 2 AND maxSpeed > 22 | שני התנאים יחד (AND); "לא כולל" ⇒ > ולא >= |
| (4) | cmd | ה־adapter מריץ את הפקודה cmd |
| (5) | Fill | adapter.Fill(ds) ממלא את ה־DataSet בתוצאות |
| (6) | DataRow dr in ds.Tables[0].Rows | המשתנה נקרא dr (כך הוא משמש בגוף הלולאה) ועובר על שורות הטבלה הראשונה |
| (7) | tr | פתיחת שורה בטבלה; בסוף כל איטרציה נסגרת ב־</tr> |
| (8) | Response.Write | שליחת מחרוזת ה־HTML לדפדפן |
הפעולה המלאה אחרי ההשלמה:
protected void printTable(string connectionString)
{
string resultStr = "";
DataSet ds = new DataSet();
SqlConnection connection = new SqlConnection(connectionString);
SqlCommand cmd = new SqlCommand();
cmd.CommandText = " SELECT * FROM [dbo].[VehicleTable] where wheels = 2 AND maxSpeed > 22";
cmd.Connection = connection;
connection.Open();
SqlDataAdapter adapter = new SqlDataAdapter(cmd);
adapter.Fill(ds);
connection.Close();
resultStr += "<table dir=rtl><tr><th>name</th> <th>wheels</th> <th>maxSpeed</th>";
resultStr += "<th>day</th><th> evening </th></tr>";
foreach (DataRow dr in ds.Tables[0].Rows)
{
resultStr += "<tr>";
resultStr += "<td>" + dr["name"] + "</td>";
resultStr += "<td>" + dr["wheels"] + "</td>";
resultStr += "<td>" + dr["maxSpeed"] + "</td>";
resultStr += "<td>" + dr["day"] + "</td>";
resultStr += "<td>" + dr["evening"] + "</td>";
resultStr += "</tr>";
}
resultStr += "</table>";
Response.Write(resultStr);
}(בשאלון מחרוזת הכותרת "<table dir=rtl>...<th>maxSpeed</th>" נשברה לשתי שורות בהדפסה, ו־dr[“wheels"] מודפס עם מירכאה מעוצבת; בקוד אמיתי המחרוזת כתובה בשורה אחת והמירכאות רגילות, כמו למעלה.)
בדיקה – הפעולה המלאה על נתוני VehicleTable משאלה 7. מבין הכלים הדו־גלגליים: קורקינט (20) ואופניים (15) אינם עומדים בתנאי maxSpeed > 22; נשארים:
| name | wheels | maxSpeed | day | evening |
|---|---|---|---|---|
| אופניים חשמליים | 2 | 35 | 95 | 80 |
| מכונית | 2 | 100 | 250 | 100 |
(אוטובוס ומשאית נפסלים כי יש להם 4 גלגלים.) אותה תוצאה מתקבלת גם מהשאילתה SELECT * FROM VehicleTable WHERE wheels = 2 AND maxSpeed > 22.
טעות נפוצה: לכתוב ב־(3) OR במקום AND (אז יוצגו גם האוטובוס והמשאית), או maxSpeed >= 22 למרות ש"לא כולל". ב־(6) לשכוח את הטיפוס DataRow או לכתוב ds.Rows – ל־DataSet אין Rows, רק לטבלה שבתוכו (ds.Tables[0].Rows).
protected void printTable(string connectionString)
{
string resultStr = "";
DataSet ds = new DataSet();
SqlConnection connection = new SqlConnection(connectionString);
SqlCommand cmd = new SqlCommand();
cmd.CommandText = " SELECT * FROM [dbo].[VehicleTable] where wheels = 2 AND maxSpeed > 22";
cmd.Connection = connection;
connection.Open();
SqlDataAdapter adapter = new SqlDataAdapter(cmd);
adapter.Fill(ds);
connection.Close();
resultStr += "<table dir=rtl><tr><th>name</th> <th>wheels</th> <th>maxSpeed</th>";
resultStr += "<th>day</th><th> evening </th></tr>";
foreach (DataRow dr in ds.Tables[0].Rows)
{
resultStr += "<tr>";
resultStr += "<td>" + dr["name"] + "</td>";
resultStr += "<td>" + dr["wheels"] + "</td>";
resultStr += "<td>" + dr["maxSpeed"] + "</td>";
resultStr += "<td>" + dr["day"] + "</td>";
resultStr += "<td>" + dr["evening"] + "</td>";
resultStr += "</tr>";
}
resultStr += "</table>";
Response.Write(resultStr);
}טבלת התשובות
| שאלה | סעיף | תשובה |
|---|---|---|
| 1 | - | ג. אובייקט השומר מידע עבור משתמש מסויים. |
| 2 | - | SELECT name FROM Games WHERE win >= lost; |
| 3 | - | טבלה עם מסגרת, בעלת עמודה אחת ושתי שורות: בשורה הראשונה 3 ובשורה השנייה 7. |
| 4 | א | b |
| ב | עוטפים את התמונה בתגית קישור: | |
| 5 | - | if ((int)Session["age"] < 13) Response.Redirect("kids.aspx"); |
| 6 | - | function getType(domain) { var parts = domain.split("."); return parts[2]; } |
| 7 | - | SELECT name FROM VehicleTable WHERE day < evening OR day + evening > 100 OR maxSpeed BETWEEN 30 AND 75; |
| 8 | - | if (ds.Tables[0].Rows.Count == 0) |
| 9 | - | (1) connectionString |