אשמח להסבר: MySqlCommandBuilder
-
בס"ד
ראשית, הפעם אני לא תקוע. הכל עובד למישרין ב"ה.
אלא שבכדי לא לעשות מעשה קוף בעלמא - הייתי שמח אם מישהו יתנדב "בזמנו הפנוי" להסביר לי משהו.לצורך חימום האצבעות, התחלתי לכתוב ב vb.net תוכנה לקריאה וכתיבה של מסדי הנתונים שלי ב MySQL.
בתוכנה יש DataGridView שמציג את תוכן הטבלאות.
בכדי שאוכל לעדכן את המסד על פי השינויים בטבלה שבתוכנה,
הלכתי על פי ההמלצה כאן (ועמכם הסליחה שלא שאלתי מלכתחילה בפורום )
וכתבתי את השורות הבאות שיתבצעו כאשר אני לוחץ על לחצן "עדכון המסד":tblMain.EndEdit() ' טייבל מיין - זה השם של הדטה גריד dataAdapter.Update(result) ' רזולט - זה השם של הדטה סט - מקור הנתונים של הדטה גריד
אלא שאז קיבלתי את השגיאה: @Visual Studio :evil:
Update דורש InsertCommand חוקי כאשר מועבר אוסף של DataRow עם שורות חדשות.
קראתי יותר לעומק את כל הדוגמא באתר הנ"ל,
וראיתי שפספסתי שורה נוספת בשלב קריאת הטבלה - שאכן פתרה את הבעייה:Dim cb As New MySqlCommandBuilder(dataAdapter)
אלא שאין לי שמץ מושג מה זה המשתנה הזה (שאינו בשימוש בשום מקום) ואיך הוא פותר את הבעייה,
ובפרט שהוא מוגדר בכלל ב"שגרה" של קריאת הנתונים שנסגרה והסתיימה מזמן.תודה רבה על קריאת כל הפוסט, וק"ו למי שאכן יסכים לסבר את אוזני בנושא.
פורסם במקור בפורום CODE613 ב27/11/2017 17:42 (+02:00)
-
הפונקציה update היא בסה"כ עטיפה למשפט SQL שמעדכן את הטבלה.
ה MySqlCommandBuilder הוא היוצר של משפט הSQL.
גם אחרי שיצאת מהפונקציה של קריאת הנתונים, הוא לא נעלם. כי הוא שייך לאובייקט dataAdapter שהוא גלובלי אתלך.פורסם במקור בפורום CODE613 ב27/11/2017 22:25 (+02:00)
-
תודה על התגובה,
אבל עדיין לא הצלחתי לתפוס.הרי לכאורה היוצר של משפט ה SQL לא קשור ל Builder,
כל השאילתות עבדו לי כראוי באמצעות הקוד הבא ובלי שום קשר ל Builder:Dim command As New MySqlCommand ' שים לב, לא בילדר!!! command.Connection = conn ' conn: משתנה המכיל את פרטי החיבור command.CommandText = txtManual.Text ' txtManual.Text: טקסטבוקס המכיל את נוסח השאילתא dataAdapter.SelectCommand = command
כל ה Builder נצרך רק לשלב של העדכון האוטומטי מהטבלה-בתוכנה אל המסד - "מתחת למכסה מנוע" - שאין לי מושג איך בדיוק הוא מתבצע.
כמו כן, לא הצלחתי להבין,
נכון שה-dataAdapter הוא גלובלי,
אבל המשתנה המיוחד שיצרנו כ- new MySqlCommandBuilder, ובלעדי משתנה זה העסק לא עובד - מת בסוף השגרה, לא?פורסם במקור בפורום CODE613 ב28/11/2017 00:18 (+02:00)
-
בדיוק כמו שמנצפך ענה.
תוכל להבין יותר ע"י שתעשה Break point לפני הUpdate ותחטט בdataAdapter.UpdateCommand.CommandText.
שים לב שקפצת מלומר לנו איך טענת את המידע, הרי ע"י פקודת SQL. כמו שהזנת ידנית את זו, היה עליך להזין ידנית את הפקודה עבור עדכון (פקודה שמבוצעת בלולאה עבור כל שורה ששונתה בDGV).
פה חסכה לך המחלקה MySqlCommandBuilder שפשוט יוצרת משפט עדכון פשוט לפי סכמת הטבלה שנטענה.
היא מכניסה משפט עדכון לUpdateCommand ומחיקה לDeleteCommand והוספה לInsertCommand.
אחרי שהכושי עשה את שלו הוא יכול ללכת וזה קורה לכאורה בסוף השגרה, אם כי ההנחה שלך לא נכונה: לא כל משתנה בתוך שגרה מת בסוף שגרה, למשל: יש לך משתנה כללי במחלקה, ויש לו מאפיין X. בתוך שגרה אתה משים new לתוך הX, הוא יחיה לאורך חיי המשתנה הכללי.
הכלל הוא שאובייקט ששום דבר לא מצביע עליו בשום מקום, נמחק אוטומטית.פורסם במקור בפורום CODE613 ב28/11/2017 00:26 (+02:00)
-
@םןץףך ו @דוד ל.ט. - תודה רבה!
דוד, אחרי שהסברת לי לאט - הבנתי מהר :lol:
בזכותך הבנתי מה קורה מתחת למכסה מנוע,
ואז חזרתי לתשובה של םןץףך והבנתי "איך זה נכנס" במה שהוא ענה.על מי לסמן V של Answered?
לריב! אין מספיק לכולם! :mrgreen:ואגב אורחין, לאחר שביארתם איך זה עובד,
אז אני מבין שלא מומלץ להריץ עדכון אוטומטי בעזיבת כל תא, אלא רק בלחיצה "בידיים" על לחצן עדכון,
כי למשל, אם יש לי (או יותר נכון: יש לי) טבלה עם 100,000 רשומות (כל הטלפונים שנכנסו למרכזייה בשנתיים האחרונות),
אם כל update הוא צריך לרוץ בלופ על כל השורות ולבדוק אם יש שינויים ואם כן לעדכן -
זה טיפשי לעשות את זה על כל תא ותא מחדש. נכון?פורסם במקור בפורום CODE613 ב28/11/2017 00:37 (+02:00)
-
כל שורה בDGV מיוצגת ע"י אובייקט בשם DataRow.
ברגע שהוא עובר שינוי, הוא מקבל במאפיין RowState שלו את הערך Modified.
כשמבצעים dataAdapter.Update(result) הדטה אדפטר מבקש מהresult את כל השורות שהוכנסו/עודכנו/נמחקו לפי מאפיין הRowState שלהם, עליהם בלבד מופעלים הקומנדים פר שורה. אם אין שורות כאלו (כל השורות הם Unchanged) לא קורה כלום. הלולאה למצוא שורות אם מאפיין כזה או אחר באובייקטים בזיכרון היא מהירה מאוד ואתה יכול להפעיל אותה כל שניה.פורסם במקור בפורום CODE613 ב28/11/2017 00:57 (+02:00)
-
בס"ד
ברשות הקהל הקדוש,
רק עוד שאלה קטנה על עדכון פר תא (לא ממש קריטי לי, יש לי לחצן עדכון שעובד יפה).כתבתי את השורה שעושה Update למסד - בשגרה שהטריגר שלה הוא CellEndEdit.
התוצאה: יום אסל יום בסל. פעם עושה את העבודה ופעם לא.
לא יודע בדיוק במה זה תלוי, אולי לאיפה זזים עם העבר / חיצים כאינדיקציה לסיום עריכת התא - למעלה למטה או ימינה שמאלה. לא יודע.מצאתי את זה בסטאק,
אבל גם הפעם יש לי הרושם ש**@ארכיטקט** (שאגב, נעלם לנו מהרדאר :() לא היה נהנה משיטות כאלו - בלשון המעטה...אשמח להחכים "בדרך הישר והרצוי"...
תודה רבה!
פורסם במקור בפורום CODE613 ב29/11/2017 22:56 (+02:00)
-
אני לא יודע, אבל תוכל לעשות טסט קטן - תעשה אירוע לDataTable שלך:
AddHandler result.Tables(0).RowChanged, Sub(s,e) Text = e.Row(0)
ותראה מתי זה קופץ. לדעתי זה יקפוץ רק במעבר שורה וזה הבעיה: כשאתה יוצא מתא יש עדכון ברמת תא, אבל מקור הנתונים מעודכן רק ביציאה מהשורה.
אם כנים דברינו, אז אני רואה באינטרנט שהפתרון הוא לקרוא לDataGrdidView1.EndEdit באירוע CellEndEdit, לפני הקריאה לUpdate.
ההסבר למה הבעיה קיימת היא שיש סיבוך אפשרי בעדכון ישיר ברמת התא למקור הנתונים. כי במקור הנתונים יכול להיות אילוץ רב תאי, למשל אם תא א' ריק אסור לב' להיות ריק, או שערך תא ב' חייב להיות גבוה משל א'. בעדכון ברמת התא לעולם לא יוכלו להתחיל מתא ב', וזה פגיעה אנושה בUX. לכןם הנורמה היא עדכון ברמת שורה.פורסם במקור בפורום CODE613 ב30/11/2017 00:07 (+02:00)
-
@דוד ל.ט.
AddHandler result.Tables(0).RowChanged, Sub(s,e) Text = e.Row(0)
תודה על תשובתך,
קודם כל, 2 הערות שוליות:
א. ב-AddHandler ששלחת, הוא צעק משהו על ה-e של ה Sub,
אז עשיתי את ה-AddHandler בדרך הישנה והטובה עם AddressOf ששולח ל Sub שיצרתי בשם test, וזה עבד.
ב. הרעיון לשנות את הכותרת של החלון לתוכן שבעמודה 0, לא מקפיץ לעין - אם נעשו שינויים בעמודות אחרות - גם שלא באשמת ה CellEndEdit.
מה שעשיתי למעשה זה פשוט שיקפיץ MsgBox עם התרעה על השינוי.בכל אופן, לעניינינו, אני התייאשתי והרמתי ידיים...
אכן, באירוע RowChanged - ההתראה על השינוי קופצת רק במעבר לשורה אחרת, ולא בתזוזה ימינה שמאלה, ולא במחיקת שורה שלמה.
העברתי את ה MsgBox שלי לשגרה של ה CellEndEdit, והוא התחיל לקפוץ גם בתזוזה ימינה ושמאלה, אבל לא במחיקת שורה שלמה,
אבל למעשה - בטבלה הוא לא מעדכן, [u:33olyrwl]גם לא במעבר שורות[/u:33olyrwl]! ולמרות שהמ-MsgBox קפץ.
הוספתי כהצעתך את הפקודה tblMain.EndEdit לשגרה של "CellEndEdit" - אבל שום דבר לא השתנה.
אז לפי מה הוא מחליט מתי כן לעדכן? לא עליתי.למעשה, אחרי ששרפתי מידי הרבה זמן ואנרגיה בדבר שכרגע למעשה די מיותר לי, כי הלחצן הידני עושה הכל כמו שצריך,
אז החלטתי לפרוש, וכשם שלא קיבלתי שכר על הדרישה, כך לא אקבל שכר על הפרישה. :lol:פורסם במקור בפורום CODE613 ב01/12/2017 03:15 (+02:00)
-
אכן בדקתי את הפתרון והוא לא עוזר.
בקשר להערותיך:
א. אכן לא שמתי לב כי אני הרצתי את זה בlinqpad, זה בגלל האות e היא תפוסה, אם תחליף לאות אחרת זה יעבוד (או תשנה את הe של חתימת המתודה בה אתה נמצא)
ב. באמת... לא התיימרתי לדעת. ואף פעם אל תטרח לשים msgbox. שים מתודה ריקה עם ברייקפוינט ואז יש לך גישה לכל הפרטים בעולם.
ג. מחיקה - לא אמורה לקפוץ (יש אירוע אחר לזה), זה רק היה טסט להבין את הDataGridView.
ד. אצלי הוא כן עדכן במעבר שורה.אני באמת לא מצאתי דרך אף שבעבר הרחוק עשיתי זאת בבירור.
עכ"פ כעת מצאתי דרך רק עם BindingSource, אני עייף אז אני מצרף קוד בלבד ללא הסברים:Dim ds As DataSet Dim binding As BindingSource Public Sub New() ds = New DataSet Dim dt = New DataTable dt.Columns.Add("A") dt.Columns.Add("B") dt.Rows.Add({"1", "FIRST"}) dt.Rows.Add({"1", "LAST"}) ds.Tables.Add(dt) InitializeComponent() AddHandler ds.Tables(0).RowChanged, Sub(s, e) ' ListBox1.Items.Add("ROW MODIFIED!") ' ListBox1.Items.Add("ROW VALUE: " & String.Join(",", e.Row.ItemArray)) End Sub binding = New BindingSource() binding.DataSource = ds.Tables(0) DataGridView1.DataSource = ds.Tables(0) End Sub Private Sub DataGridView1_CellEndEdit(sender As Object, e As DataGridViewCellEventArgs) Handles DataGridView1.CellEndEdit binding.EndEdit() End Sub
תראה בהזדמנות זו שפתחתי פרוייקט WinForms אחרי הרבה זמן שלא עשיתי זאת, אעיר לך שברגע שהתצוגה תתחיל לתפוס לך זמן אז תעבור מיידית לWPF...
פורסם במקור בפורום CODE613 ב01/12/2017 11:57 (+02:00)
-
בס"ד
תודה על התשובה והקוד,
בינתיים כנראה אני אשאר עם העדכון הידני ע"י הלחצן,
ואזכור לעתיד אם יהיה צורך - שיש פתרון מוכן של @דוד ל.ט. ב-Code613M.לגבי WPF, הערה נכונה (התעסקתי לא מעט עם התצוגה גם בתוכנה זו - עם חלוקה לכמה וכמה פנלים וספליטר),
אבל, WPF היא שפת תגיות, ולהזכיר - HTML אצלי עדיין רק בתכנון (לעתיד הקרוב),
וכן JS והרבה שפות נוספות שארצה להכיר כנראה בקרוב - בנויות על תחביר דומה למשפחת C,
לכן לדעתי אני קודם אשקיע על שלישיית HTML+CSS+JS כדי "לפרוץ קדימה" בתחום חשוב שאצלי עדיין לא מוכר,
ואחרי זה בעז"ה אחזור כבר לעולם החדש של C#+WPF במקום ל VB הענתיקה (שכמו הרבה, התחלתי איתה דרך VBA של Word 95-97).תודה רבה!
פורסם במקור בפורום CODE613 ב01/12/2017 12:29 (+02:00)
-
אין שום צורך להכיר את התגיות בתור התחלה לפחות! יש דיזייינר וחלון מאפיינים בדיוק כמו בWInForms.
ושפת תגיות זה משהו של לימוד של חמש עד עשר דקות (XML נוד אטריביוט ונייימספייס).
תרגיש חופשי לדחות את זה.פורסם במקור בפורום CODE613 ב01/12/2017 12:35 (+02:00)
-
@דוד ל.ט.
ושפת תגיות זה משהו של לימוד של חמש עד עשר דקות (XML נוד אטריביוט ונייימספייס).
אשמח אם תפנה אותי לאיפה הכי נכון ללמוד את זה - אונליין כמובן (אני מוכן להתפשר גם על חצי שעה :lol: )
בפרט למושגים שהזכרת נוד אטרביוט - שאין לי מושג אפילו מה זה, וניימספייס שלא חלמתי שיש לזה קשר גם לשפת תגיות.תודה רבה!
פורסם במקור בפורום CODE613 ב01/12/2017 13:29 (+02:00)
-
עוד הערה, ללמוד JS כהקדמה לC#, עלול להיות כואב מאוד... אני מאוד בעד ללמוד JS, אבל אל תשים את זה כצעד מקדים לסי שארפ (הקשר החיצוני שלהם מטעה מאוד).
אם כבר תלמד VB.NET חזק כהקדמה לC#. הם שפות דומות מאוד, ההבדלים כמעט רק תחביריים.פורסם במקור בפורום CODE613 ב01/12/2017 13:31 (+02:00)
-
אחד הסודות הכי גלויים כאן בפורום, הוא דעתך @דוד ל.ט. גבי דוט נט vs ג'אוה סקריפט ושאר החבר'ה
העניין הוא, שכרגע אם אני צריך תכנות לוקאלי ל Windows, אני מסתדר לא רע עם VB.NET.
תכנות WEB'י אני לא מכיר בכלל ומאד הייתי רוצה להכיר,
אבל אישית דווקא הייתי מעדיף להתחיל להשתולל עם הצד המופרע של JS ו NodeJS (ואולי גם PHP),ואם אצטרך תוכנות לוקאליות בדווקא, אני מניח שאחרי שאשחה כמו דג ב HTML ו JS,
לא תהיה לי בעייה גדולה ליישם ב-C# את התחביר שלהן עם הידע שכבר יש לי מ-VB.לדעתך אני מקשקש כאן שטויות?
אתה משום מה מזכיר לי את המשל של המסילת ישרים על האדם שעומד על האכסדרה בגן המבוכה...פורסם במקור בפורום CODE613 ב01/12/2017 14:00 (+02:00)
-
ואם אצטרך תוכנות לוקאליות בדווקא, אני מניח שאחרי שאשחה כמו דג ב HTML ו JS,
לא תהיה לי בעייה גדולה ליישם ב-C# את התחביר שלהן עם הידע שכבר יש לי מ-VB.אפשר היום לעשות תוכנות לוקאליות עם nodejs עם הכלי הזה.
https://electronjs.org/למשל
https://desktop.github.com/
זה בנוי על בסיס אלקטרון.גם vscode. שעשתה את זה החברה שדוד מאוד אוהד.
https://github.com/Microsoft/vscode
בנוי על אותו רעיון.פורסם במקור בפורום CODE613 ב01/12/2017 15:22 (+02:00)
-
@איש אחד, כתבתי לך כבר, אין לי מה להוסיף.
אין לזה שום קשר לדעתי השלילית עם JS, גם חסיד מושבע של JS לא יצדיק לימוד JS כהקדמה לC#. וזה גם לא שפה מסובכת שצריכה הקדמות וגם לא חשובה כ"כ ללימוד אם אתה יודע VB.NET.
בקשר לנוד אני מאוד אשמח אם תלמד אותה טוב ושתישאר שמה, ככה יהיה פה (עוד) אחד בפורום שיודע את זה טוב.פורסם במקור בפורום CODE613 ב02/12/2017 21:13 (+02:00)