נחזור לנושא
האם תשובה זו עוזרת לך?
https://github.com/RVC-Project/Retrieval-based-Voice-Conversion-WebUI/issues/2227#issuecomment-2286582025
נחזור לנושא
האם תשובה זו עוזרת לך?
https://github.com/RVC-Project/Retrieval-based-Voice-Conversion-WebUI/issues/2227#issuecomment-2286582025
@יגעתי-ומצאתי אני מתנצל. אני מבין שסגנון הכתיבה שלי היה מתנשא ומעליב. מטבע הדברים בתקשורת על גבי דפי הפורום יש הרבה ניואנס ש"נאבד בתרגום". ואני שמח ש"לא יכולת דבר עמי בשלום" במקום לשמור את הפגיעה בלב.
אני עדיין עומד מאחורי תוכן הדברים שלי, אם כי לא מאחורי הסגנון.
כי אני אדם אֲנֹכִי, ואני פעיל בפורום כי אני מקבל מזה הנאה. ההנאה של פתרון בעיה מסובכת, או ההנאה של עזרה לשני. במשא ומתן שכולל רק הצגת שאלות קצרות וסיפוק תשובות, אני מתחיל להרגיש פרייר, וזה לא עושה טוב לאנכיות שלי.
לכשתמצא לומר, אני הילד הקטן שצריך איכשהו לפייס את יצרו באיזה ממתק בצורת שיכנוע שבאמת אני עוזר לשני בדבר שהוא לא יכל לעזור לעצמו, או שיש פה בעיה מסובכת שצריך להפשיל שרוולים בשבילו.
אגב, בנוגע לאות ב) לעיל, הבנתי שלכאורה שחסר לך חלק מהרקע להבין לעומק מה כתוב בשגיאה (זה דבר שגם הרבה מתכנתי פייתון בני נסיון מועט לא בהכרח יבינו). במקרה כן הבנתי מה שכתוב בשגיאה והתחלתי לכתוב את זה בתשובה מרצון טוב לשתף ידע כי אני לא אוהב לשמור דברים לעצמי אלא לשתף.
אבל אז ראיתי שזה יעלה במאמץ מצדי ושיערתי שלכאורה חיפוש גוגל יכול להוביל לפתרון יותר מהיר מללמוד לעומק כל הרקע כדי שתבין לעומק מה היתה הבעיה. אז עשיתי חישוב והחלטתי שקודם נראה אם חיפוש גוגל יעזור, ואם לא אז אני מוכן בשמחה להתעמק יותר.
אבל אז טען לי היצר הרע שאני לא המשרת שלך שאמור לחפש בגוגל, מצד שני טען יצרי הטוב שאולי כבר חיפשת ולא מצאת פתרון מספק, ואז טען לנגדו היצר הרע שאם כבר חיפשת ומצאת אנשים מדברים על זה היית מזכיר את הפתרון המוצע ומפרט למה זה לא עבד לך.
הויכוח הפנימי הסתיים עם טענה זו עם נצחון לכאורה ליצר הרע
@יגעתי-ומצאתי בשלב הזה יותר אעזור לך אם במקום להביא לך תשובה, אכוון אותך איך לפתור לבד
אגב, אני לא מכיר את RVC משום מקום, עד עכשיו פתרתי את הבעיות עם קריאה זהירה של השגיאה וקריאת תיעוד (ביחד עם הבנה שמגיע מנסיון של הרבה שנים).
א) טוב שהצלחת למקד את השגיאה לשורה מסויימת של הפלט, זו התחלה מצויינת
ב) בעיקרון, לפני הכל אתה צריך לנסות להבין מה אומר השגיאה
אבל אני לא בטוח שיש לך מספיק רקע להבין, יש כמה ידיעות נחוצות שצריך כדי להבין מה השגיאה אומרת
אז נעבור לשלב ג
ג) מעתיקים את טקסט השגיאה לגוגל ומחפשים
פה למזלך יש הרבה תוצאות וחלק מהם מדברים בדיוק על RVC (למרות שהכנסתי לחיפוש רק שלוש מילים מהשגיאה)
עכשיו הכדור אצלך...
(לא בדקתי אם יש פתרון קל במראי מקומות של גוגל. אני משאיר לך את העבודה. בתקווה להבנה)
כתוב בפלט של השגיאה שזה אמור להיות במיקום זה (יחסית לתקייה הראשית)
assets/hubert/hubert_base.pt
תוריד את שניהם ושים אותם בתקיית C:\Users\user\Retrieval-based-Voice-Conversion-WebUI
כך הבנתי מתרגום גוגל
@קומפיונט כתב בGitHub Copilot עכשיו בחינם:
ואגב, למי שלא אוהב לשתף קטעי קוד שלו עם GitHub
כמובן שזה רלוונטי רק למי שמשקיע בקוד שלו ולא נותן ל-AI לחבר בשבילו הכל...
(סליחה, לא שלטתי בעצמי, יש לי הרבה קיטור לשחרר נגד אנשים שעושים שימוש יתר ולא נכון ב-AI...)
@קן-ציפור כתב בעדכון ושדרוג פורום NodeBB:
האם שווה לקחת את הסיכון לשדרג?
יום לאחר התקנה? נראה לי שאין בזה כל כך סכנה. בעיקרון שידרוגי DB אמורים לזרום בלי בעיה, ההמלצה לגבות הוא רק ליתר ביטחון. מה גם שלא בכל עדכון גירסה יש עדכון סכמה ל-DB.
אפשר לבדוק איזה שידרוגי DB יש בגירסה מסויימת על ידי
ls src/upgrades/x.x.x
תחליף x.x.x
במספר הגירסה
כיצד מגבים את הפורום שכאמור משתמש ב- PostgreSQL?
PGDATABASE=<db_name> PGUSER=<db_username> PGPASSWORD=<db_password> pg_dump -Fc -f <output_filename>
תחליף כל מה שנמצא ב-<>
בערכים מתאימים
ותדביק לטרמינל ותלחץ אנטר
תקבל קובץ גיבוי בשם <output_filename>
(כלומר הערך שבחרת להכניס שם) שאפשר לשחזר אותו עם פקודת
pg_resore
במקרה הצורך
טיפ: כדאי להכניס את התאריך של היום לתוך שם הקובץ - אם זה פקודה שאתה הולך להריץ מפעם לפעם, כך תדע מאיזה תאריך הגיבוי
ע"ע: https://www.postgresql.org/docs/current/app-pgdump.html
או man pg_dump
@יגעתי-ומצאתי כתב במערכת לניהול תורמים יעבוד גם עם אתר?:
בכ"א אשמח לדעת מה הDB שהכי טוב עבור זה
אציין שכבר התחלתי עם משהו ממש קטן בSQL אבל אני ממש לא אוהב את זה, אני מעדיף משהו יותר נוח.
(חוץ משהו שאני לא יודע איך מחברים את זה לאתר)
אין לי מספיק פרטים לענות לך פה תשובה טובה מותאמת אישית
בעיקר חסר לי הידיעה איזה תחומים של תכנות/בניית אתרים אתה מכיר ובאיזה רמה
המילה "SQL" לא ברורה לגמרי, כי SQL היא שפת שאילתות ולא מסד נתונים. אני מניח שאתה מתכוון למשפחה שלמה של מסדי נתונים שבד"כ מתשאלים ב-SQL.
הם מוכרים בצורה יותר רשמית כ-relational databases (מסדי נתונים יחסיים), זה כולל הרבה מסדי נתונים, המפורסמים מתוכם הם sql server, mysql, postgres, sqlite. גם אקסס נמצא בקטגוריה זו.
יש הרבה דרכים לפניך
הכיוון הכי קלאסי באתר כמו זה הוא להשתמש במסד SQL-י מהנ"ל
גם בזה אפשר לבחור באחסון עצמי או באחסון מנוהל שזה שירות ענן מאחסן בשבילך המסד - אחסון עצמי יותר זול, אבל צריך ניהול.
אם תבחר ב-sqlite אין שום ניהול כי זה פשוט קובץ שיושב על השרת.
להתחבר למסד כזה צריך ידע בתכנות, והצורה להתחבר תלוי באיזה שפה אתה משתמש
יש סוג אחר של מסד שידוע כ-nosql, המפורסם מביניהם הוא mongodb, זה נושא בפני עצמו להסביר היותרונות והחסרונות שלו לעומת מסדים האחרים,
גם שם אפשר לבחור בין אחסון עצמי למנוהל, וכמו האחרים צריך ידע בתכנות כדי לחבר אתר אליו
מכיון שכבר התחלת בצורת החשיבה של relational databases (טבלאות עם קישורים בין הטבלאות) אני מניח שככה תרצה להמשיך
בצד השני של הסקלה יש שירותים כמו nocodb ו-airtables שנותנים ממשק גרפי ומאפשרים הרבה פעולות בלי לכתוב שורת קוד
יש גם דברים באמצע כגון https://supabase.com. צריך לכתוב קוד אבל מאוד קל להתממשק איתו
אגב, אני לא לוקח אחריות על הפלטפורמה... אני מכיר אותה בדיוק כמוך, כאשר ציינתי את שמה לא התכוונתי להמליץ עליה. מקווה שלא תיתקל בבעיות. מכיון שמדובר בשירות מסחרית אפשר להניח שדברים בד"כ עובדים טוב.
@יגעתי-ומצאתי לגבי המחיקה, הסיבה שלא יכולת למחוק הוא מפני שהעמודה מוגדרת כ-Display Value Field - הכוונה שהעמודה משתמשת עבור הצגת השורה (כאשר מקשרים שורה זו לטבלה אחרת השורה מוצגת על ידי התוכן של עמודה זו)
הפתרון הוא להחליף את ה-Display Value Field לעמודה אחרת (איזה עמודה שתבחר תעבור למיקום הראשון בטבלה - אחרי המספר)
@יגעתי-ומצאתי כתב במערכת לניהול תורמים יעבוד גם עם אתר?:
אבל משום מה אני לא מצליח למחוק חלק מהעמודות
גם אני, ניסיתי לבדוק, ובינתיים לא מצאתי פתרון. מקווה שזה לא באג אצלם.
אגב, לשנות את הtype של התאריך ושעה ג"כ לפורמט של תאריך ושעה ולא של טקסט, נכון?
כן
מה הרווח בזה?
יש פונקציות שעובדות על תאריך/שעה, למשל סינון לפי תאריך, לא מוקדם מ- או לא מאוחר מ-
זה לא יעבוד על שדה טקסט
never
נחזור שוב ל-never
לכמה רגעים
הטייפ never
הוא סט בלי חברים, טייפ ששום ערך לא יכול להיות בו חבר.
נמצא שלא יקרה אף פעם שלערך אמיתי יהיה טייפ never
אם כן לְמָה זה טייפ שימושי?
אחד מהשימושים של טייפ זה הוא לסמן ל-TS שמצב מסויים אמור להיות בלתי אפשרי, ולקבל אישור מ-TS שזה באמת בלתי אפשרי
למשל: אם רוצים לוודא שב-switch עברנו על כל האפשרויות ולא פיספסנו אחד מהם בטעות אפשר לכתוב ככה:
type Color = 'red' | 'blue' | 'green'
function handleColor(color: Color) {
switch (color) {
case 'red':
// ...
break
case 'blue':
// ...
break
case 'green':
// ...
break
default:
throw new Error('Impossible!')
}
}
פה אנחנו בודקים בזמן ריצה שלא הגענו לענף הבלתי אפשרי
אבל עם TS יש לנו אפשרות לבדוק בזמן קימפול שלא שכחנו לטפל בשום אפשרות
מוסיפים שורה זו:
type Color = 'red' | 'blue' | 'green'
function handleColor(color: Color) {
switch (color) {
case 'red':
// ...
break
case 'blue':
// ...
break
case 'green':
// ...
break
default:
const _test:never = color
throw new Error('Impossible!')
}
}
עיין שורה 15. אנחנו מצהירים ל-TS שבשלב הזה מיצינו את כל הערכים האפשריים ש-color יכול לקבל ופה הטייפ חייב להיות never, כלומר זה לא יקרה אף פעם
(להבין יותר איך זה עובד, כדאי להכיר את המושג narrowing, בקיצור נמרץ: מנוע TS עוקב אחרי משתנים תוך כדי זרימת הקוד וכאשר הוא רואה ביטויים מסויימים בקוד, הוא מבין אותם ומוציא מתוך ה-union של הטייפ של המשתנים את אותם הטייפים שהקוד שולל, ובהקשר שלנו, בכל ענף של ה-switch, מנוע TS יכיר בעובדה שהטייפ של color
הוא רק הערך שאותו ענף מטפל, ובענף default
הטייפ הוא האפשרויות שה-switch לא מיצה)
ברגע שנוסיף עוד אפשרות ל-union של Color
נקבל מיד אזהרה שהמשתנה _test
קיבל ערך שהטייפ שלו הוא לא never
אבל השימוש שמעניין אותנו יותר פה הוא השימוש השני,
כאשר יוצרים טייפ חדש באמצעות ביטוי עם תנאי, ורוצים שענף אחד של התנאי לא יחזיר שום טייפ, או יותר נכון: יחזיר טייפ ריק, במקום כזה בא never
לידי שימוש
נדגים את זה על ידי ה-helper המובנה - Exclude
(helper הוא פונקציה שעוזר לבניית טייפ שמבוסס על טייפ קיים. נזכיר: פונקציה ב-TS == generic)
הטייפ Exclude
מגיע מובנה ב-TS ושימושו הוא כאשר רוצים ליצור מ-union קיים, טייפ שדומה למקור רק שחסר ממנו אחד או יותר ערכים.
למשל:
type Weekday = 'sunday' | 'monday' | 'tuesday' | 'wednesday' | 'thursday' | 'friday' | 'saturday'
type Workday = Exclude<Weekday, 'friday' | 'saturday'>
כפי שאפשר לראות: ה"פונקציה" Exclude
מקבלת כפרמטר ראשון את הטייפ המקורי ובפרמטר השני union של טייפים (או טייפ יחיד) לחסר מהטייפ המקורי.
איך הוא עובד?
הנה קוד המקור
type Exclude<T, U> = T extends U ? never : T
להבין את זה צריך להקדים עוד דבר אחד: ביטוי של תנאי שמריצים על union עובד על כל אבר של ה-union בנפרד
בתיעוד של TS קוראים לזה: Distributive Conditional Types
כלומר זה עובד כמו הקוד פסואודו הבא:
function Conditional(source: Union, condition: Type => Bool, resultIfTrue: Type => Type, resultIfFalse: Type => Type) {
const runConditional = (type: Type) => {
if (condition(type)) {
return resultIfTrue(type)
} else {
return resultIfFalse(type)
}
}
return source.split('|').map(runConditional).join('|')
}
function Exclude(source: Union, exclusions: Union) {
return Conditional(source, t => t.extends(exclusions), t => t, t => never)
}
Exclude(Weekday, 'friday' | 'saturday') // 'sunday' | 'monday' | 'tuesday' | 'wednesday' | 'thursday' | never | never
מקווה שהפסאודו קוד מובן
רק מזכיר שוב כמה נקודות שכבר הזכרנו:
Exclude
אפשר להשמיט את ה-never
בלי שום השלכהextends
בדרך אגב, כמה אנשים שאלו שאלה זו: למה המצב שבו טייפ אחד כלול לגמרי בתוך טייפ אחר נקרא בלע"ז
extends
, הרי המשמעות של extend בלע"ז הוא "הרחבה" ופה מדובר על הצרה?!
התשובה לזה לכאורה (וכן הסכים לזה מתכנת אחר שדיבר איתי על זה) שהמילה "הרחבה" בהקשר זה לא מדבר על הסט שהוא תוצאה מהגדרת הטייפ אלא על הגדרת הטייפ עצמו,
ככל שאתה יותר מאריך בהגדרת הטייפ, כך אתה שולל יותר ויותר מועמדים פוטנציאליים.
לדוגמה: טייפunknown
הוא הטייפ הכי גדול מצד אחד, כי הוא כולל כל הערכים האפשריים, ומצד שני הגדרתו הוא הכי קצר: אין שום הגדרה, כל מה שזז נכנס לתוך הטייפ הזה. ברגע שמרחיבים את ההגדרה, למשל מוסיפים תנאי שיש לו מתודה פלונית, אתה מצר את מעגל החברים בטייפ
Omit
עכשיו נוכל להסביר את הטייפ Omit
שבו סיימנו את הפוסט הראשון, וזה אמור להיות מובן בקלות כעת
הפונקציה מקבלת בפרמטר הראשונה אובייקט, ובשנייה, union של מפתחות שאתה רוצה להשמיט ממנו
דוגמה לשימוש (מתוך התיעוד הרשמי):
type Todo = {
title: string
description: string
completed: boolean
createdAt: number
}
type TodoPreview = Omit<Todo, "description">;
שיניתי קצת מהמקור בתיעוד של TS ממילת המפתח
interface
למילתtype
רק לשם העקביות כי לא הצגנוinterface
במאמר זה - יש הבדל קטן בין השניים אבל זה נושא לשיחה אחרת ולא חשוב כעת
פה אני רוצה להתמקד על האינטואיציות המרכזיות ולא על פרטים קטנים
והנה קוד המקור של Omit
type Omit<T, K extends keyof any> = { [P in Exclude<keyof T, K>]: T[P]; }
ננתח את זה לחלקים:
Omit<T, K extends keyof any>
הפונקציה מקבלת שני פרמטרים, הראשון ברור. זה יכול להיות כל טייפ שהוא. השני מוגבל לקבל רק טייפ שמקיים בעצמו התנאי extends keyof any
מה זה keyof any
? זו דרך קצרה להגיד כל טייפ שחוקי להשתמש בו כמפתח של אובייקט כלשהו, שזה כהיום: string | number | symbol
. אז הפרמטר השני הוא טייפ שמורכב רק מדברים שמותרים במפתח אובייקט
{ [P in Exclude<keyof T, K>]: T[P]; }
יש פה שימוש בכמה דברים שהסברנו כבר למעלה, נתחיל מהפנים לחוץ:
keyof T
= מחזיר union של כל המפתחות של שדות בטייפ T
Exclude<keyof T, K>
= מוציא מתוך זה את השמות של השדות שאתה רוצה להשמיט בטייפ הסופי[P in Exclude<keyof T, K>]
מריץ לולאה על כל חבר מבודד מתוך ה-union שהתקבל מהשלב הקודם כאשר הטייפ המבודד מיוצג על ידי המשתנה P
{ [P in Exclude<keyof T, K>]: T[P]; }
= מייצג טייפ שבו עבור כל P
בלולאה, יש שדה בשם P
וערך מהטייפ T[P]
= כלומר הטייפ המקורי של שדה זו בטייפ המקוריוהנה פסאודו קוד לקינוח:
function Omit(t: Type, u: UnionOfKeys) {
const res = {}
for (key of Omit(Keyof(t), u).split('|')) {
res[key] = t[key]
}
return res
}
פשוט ביותר!
נחזור לנושא המקורי שהצגתי בכותרת
(אם חיכית בקוצר רוח לחלק זה, זה באמת לא כל כך מרעיש עולמות... מצטער...)
ולשם הקדמה אביא את הטריגר שהביא אותי להבנה זו:
מישהו שאל: איך אפשר ליצור טייפ שבו מותרים רק שדה x
ו-y
ולא שום שדה נוסף
נציין פה שיש טעות נפוצה אצל מתחילים ב-TS, שאם טייפ לא כולל שדה מסויים, אז ערך שיש בו שדה זו לא יכול להיות חבר בטייפ. זה לא נכון.
ב-TS, העובדה שטייפ לא כולל שדה מסויים, עדיין לא שולל שהשדה יכול להיות קיים.
למשל:
type HasFoo = { foo: string }
גם אובייקט שיש לו שדה bar
יכול להיות חבר בקובצת HasFoo
const hasBar = { bar: 1, foo: 'foo' }
const test:HasFoo = hasBar // no error
Object literal may only specify known properties
אם הייתי כותב בקיצור בקטע הנ"ל:const test:HasFoo = { bar: 1, foo: 'foo' }
הייתי מקבל שגיאה זו:
Object literal may only specify known properties, and 'bar' does not exist in type 'HasFoo'.(2353)
אל תתנו לשגיאה זו להטעות אותך! העובדה ש-HasFoo
לא מצהיר על שדהbar
לא מונע מחברי הסט לשאת שדות נוספות!
ההתרעה של TS הוא מסיבה אחרת: מכיון שהמשתנה היחיד שקיבל את הערך של{ bar: 1, foo: 'foo' }
יש לו טייפ שלא כולל את השדהbar
, יוצא שבפועל אין דרך להשתמש בשדהbar
. כי הגישה דרך משתנהtest
אסור כי השדה לא כלול בטייפ שלו. רוב הסיכויים הם שקוד כזה הוא שגיאה של המתכנת, לכן TS מתריע.
לעומת זאת, בדוגמה שהבאתי, ששמרתי את הערך בתוך משתנה אחר לפני ההשמה ל-test
, אין על מה להתריע מכיון ששדהbar
נשאר נגיש דרך משתנהhasBar
נחזור לשאלה: איך אפשר לשלול שדות לא מוצהרות מטייפ
ספוילר: התשובה היא שאי אפשר. וזה מתועד בתשובות ב-stack overflow ו-issues בגיטהאב
אבל אני כעקשן ניסתי בכל זאת לפתור את זה על ידי הטייפ הבא:
type T = {
x: string
y: number
}
type Exact<T> = {
[K in keyof any]?: K extends keyof T ? T[K] : never
}
מקווה שכעת קל לכם להבין את הקוד
בתרגום לאנגלית, זה אומר ככה:
בטייפ Exact<T>
: קח את הטייפ של כל מפתח חוקי אפשרי (keyof any
), עבור כל חבר מתוך מרכיביו בלולאה ותבדוק אם הוא מתוך המפתחות של T
, אם כן, הערך של המפתח בתוך התוצאה צריך להיות כמו ב-T
(המקור); אחרת הטייפ צריך להיות never
- דבר שכמובן לא יכול להיות
לכאורה יצא לנו טייפ שאוסר מפתחות מיותרות
התשובה היא מה שכתבתי בכותרת: "טייפ X לא זהה ל-union של כל הערכים האפשריים שהטייפ כולל"
כלומר, הלולאה של K in keyof any
שמפרק את keyof any
למרכיביו, ומעביר כל מרכיב בודד בלולאה, לא מפרק את הטייפ string
לכל מחרוזת אפשרית. בהקשר זה string
הוא אטומי. כמו"כ number
.
היה אפשר לחשוב אחרת, כי סה"כ הטייפ string
הוא סה"כ סט שמחובר מכל המחרוזות האפשריים ביקום. אבל לצערנו TS לא מסתכל על זה ככה. אלא מתייחסים ל-string
כאטום. ולכן בלולאה K in keyof any
יש התייחסות רק ל-string
ו-number
ו-symbol
ולא לערכים הפרטיים שמרכיבים אותם. כמובן, אם ככה, ההמצאה שלי לא תעבוד כי התנאי K extends keyof T
אף פעם לא יתקיים
עוד דבר שאנשים מבקשים מפעם לפעם (עיין דברי ימי שאלות SO ואישיו-אים של GH) הוא טייפ שמייצג כל מחרוזת אפשרית חוץ ממחרוזות ידועות לשמצה. למשל
type NotWeekday = Exclude<string, Weekday>
אנשים מצפים שדבר כזה יעבוד. אבל זה לא עובד. ולפי הנ"ל זה מובן
נזכיר את קוד המקור של Exclude
type Exclude<T, U> = T extends U ? never : T
הטייפ מתבסס על העובדה שלפני בדיקת התנאי יש פירוק של T
למרכיביו ובדיקת התנאי רץ על כל מרכיב בנפרד (Distributive Conditional Types)
אבל לצערנו, הטייפ string
הוא אטומי. הוא לא מתפרק לכל המחרוזות שמרכיבים אותו. לכן התנאי T extends U
אף פעם לא מתקיים
תם ולא נשלם
@pcinfogmach כתב בDebugging על ViewModel ב-WPF:
הבעיות מתחילות כאשר אני משתמש במבנה MVVM ויש בעיה במודל או ב-ViewModel
ניסיתי גם ככה, ולא הצלחתי לשכפל את הבעיה שלך...
הוספתי ל-vscode תוסף template studio ויצרתי פרוייקט עם מבנה MVVM וכל שאר ה-goodies שהם מציעים
הוספתי ל-viewmodel אקראי איזה חריגה בטיפול של אירוע, ו... הכל עובד מצויין, הדיבגר נעצר בדיוק על החריגה
מה שונה אצלך?
יצויין שכל ההגדרות אצלי הם בררות מחדל
@יגעתי-ומצאתי כתב במערכת לניהול תורמים יעבוד גם עם אתר?:
ומה צריך להוסיף \ לשנות בטבלאות
תמחק מכל טבלה את העמודה ID כי העמודה הכי שמאלית עם הכותרת "#" הוא ה-ID
איך מקשרים ביניהם
למשל בטבלה "רשימת מתרימים" תלחץ על החץ למטה בכותרת העמודה "שיעור ID" ושנה את ה-type ל-link, בתיבה שנפתח תבחר Relation Type = One to One ובבחירת טבלאות תבחר "רשימת שיעורים"
כנ"ל לגבי כל עמודה שהוא קישור לטבלה אחרת
מובן?
@יגעתי-ומצאתי כתב במערכת לניהול תורמים יעבוד גם עם אתר?:
יש לזה איזשהו מדריך בעברית אולי?
מן הסתם לא
@יגעתי-ומצאתי כתב במערכת לניהול תורמים יעבוד גם עם אתר?:
שהנתונים יטענו משם, ואז החישבון יהיה באתר עצמו.
או ששם אני יעשה את החישבון ואתר יטען ישר את הנתונים ויציג אותם כגרפים? (כמו שהיה עד עכשיו עם הגוגל שיטס)
לענ"ד השיקול העיקרי הוא שתעשה מה שיותר נוח לך
אבל יש יתרון כלשהו שהחישובים יהיו שמורים בקוד, כי יש הרבה כלים לניהול קל של קוד. כמו ניהול גירסאות עם גיט וכדומה. זה גם יותר נגיש לך, לא צריך לעבור כמה מסכים בתוך אתר להגיע לחישוב.
זה גם תלוי באופי החישובים. כמה לוגיקה יש בהם. כמה זה עלול להשתנות במשך חיי המוצר.
אגב, אני לא מפתח WPF אבל יצרתי פרוייקט דמו כדי לבדוק את הנושא
הוספתי לפרוייקט שלי UserControl ובתוך הconstructor זרקתי שגיאה
אצלי הדיבאגר עוצר בתוך הקוד שלי בשורה שאני זורק את השגיאה (ב-catch ולא בזריקה הראשונה בתוך ה-try)
אני לא יודע מה שונה אצלך, אם זה שינוי של הגדרות, או קלאס שונה של exception
שים לב בתמונה גם לכותרת הודעת השגיאה (User-Unhandled) וגם להגדרות וקישור להגדרות נוספות
אם אני אומר לדיבגר להמשיך ולהתעלם מהשגיאה, אז אני מגיע לקוד שאתה הבאת אחרי כמה עצירות ביניים שבינתיים לא הבנתי טבען (אני צריך ללחוץ continue איזה ארבע פעמים כדי להגיע לשם)
@pcinfogmach יש כמה מצבי exception שיכולים לקרות תוך כדי דיבוג
א) חריגה שנזרקה מתוך קוד שלך והולכת להיות מטופל בתוך קוד שאתה כתבת, כלומר, זה בתוך בלוק של try/catch שאתה כתבת
ב) חריכה שנזרקה מתוך קוד שלך והולכת להיות מטופל, אבל לא על ידי קוד שלך (מי שקרא לפונקציה של הוסיף מסביב לקריאה try/catch)
ג) חריגה שנזרקה מתוך קוד ספרייה - לא קוד שלך, והולכת להיות מטופלת על ידי קוד הספרייה
ד) חריגה שנזרקה מתוך קוד ספרייה - לא קוד שלך, והולכת להיות מטופלת על ידי קוד שלך - אין בלוק try/catch של הספרייה אבל אתה עטפת את הקריאה עם try/catch
ה) חריגה שלא מטופלת כלל
הכללים מתי VS עוצר את הדיבאגר בעת זריקת חריגה תלויה בכמה הגדרות
רמה ה) תמיד גורם לדביאגר לעצור
השאר תלויים בהגדרות
במקרה שלך מדובר החריגה שנזקרה מתוך הקוד שלך וטופלה על ידי ספריית XamlLoader של הפריימוורק (כמו שאתה רואה בתמונה, כאשר נטענת קובץ xaml זה קורה בתוך בלוק של try/catch)
כנראה שההרכב של ההגדרות שלך גורמות שחריגה זו לא תעצור את הדיבאגר עד שהיא לא תגיע למצב ה) - חריגה לא מטופלת - ולכן העצירה קרתה רק בתוך קוד של הפריימוורק
אחרי הקדמה זו תקרא את תיעוד ההגדרות
https://learn.microsoft.com/en-us/visualstudio/debugger/managing-exceptions-with-the-debugger?view=vs-2022
ותבדוק אם אתה מצליח להבין למה זה קרה
שים לב שאפשר להגדיר כל תת-טייפ של exception עם הגדרה שונה, ויש גם הגדרות כלליות כמו מה ש @Mordechai-0 הביא - Just My Code
בינתיים לא התעמקתי בתיעוד בצורה מספקת להבין בדיוק הכללים