ייעול של פונקציות החיפוש
-
כתבתי חלון לחיפוש תורמים ותרומות
זה החלון:
כתבתי מחלקה אבסטרקטית עם פונקציות לחיפוש:public abstract class SearchDonor { public static IEnumerable<Donor> SearchName(string name) { var result = from donor in AddTorem.donors where donor.FirstName == name || donor.LastName == name select donor; return (IEnumerable<Donor>)result; } public static IEnumerable<Donor> SearchID(string id) { var result = from donor in AddTorem.donors where donor.Id ==int.Parse(id) select donor; return (IEnumerable<Donor>)result; } public static IEnumerable<Donor> SearchAddress(string address) { var result = from donor in AddTorem.donors where donor.Adress == address select donor; return (IEnumerable<Donor>)result; } public static IEnumerable<Donor> SearchTelefon(string telefon) { var result = from donor in AddTorem.donors where donor.Tel == telefon select donor; return (IEnumerable<Donor>)result; } public static IEnumerable<Donor> SearchEmail(string email) { var result = from donor in AddTorem.donors where donor.Email == email select donor; return (IEnumerable<Donor>)result; } public static IEnumerable<Donor> SearchGenderMale() { var result = from donor in AddTorem.donors where donor.Gender == Gender.male select donor; return (IEnumerable<Donor>)result; } public static IEnumerable<Donor> SearchGenderFemale() { var result = from donor in AddTorem.donors where donor.Gender == Gender.female select donor; return (IEnumerable<Donor>)result; } }
והקוד שמופעל כשלוחצים על הלחצן "חפש" בחיפוש לפי נתוני התורם הוא:
private void SearchDonor_Click(object sender, RoutedEventArgs e) { try { IEnumerable<Donor> result; //if all is empty string textSearch = nameSearch.Text + idsearch.Text + addressSearch.Text + telSearch.Text + emailSearch.Text; if (((string.IsNullOrEmpty(textSearch) && genderMaleSearch.IsChecked == false && genderFeamleSearch.IsChecked == false)) || (string.IsNullOrEmpty(textSearch) && genderMaleSearch.IsChecked == true && genderFeamleSearch.IsChecked == true)) throw new Exception("Eror!! Insert a value in the textbox."); //אם נבחרה רק תיבת הסימון של "זכר" else if (string.IsNullOrEmpty(textSearch) && genderFeamleSearch.IsChecked == false) { result = SearchDonor.SearchGenderMale(); viewSerchGridDonors.ItemsSource = result; } //כנ"ל של "נקבה" else if (string.IsNullOrEmpty(textSearch) && genderMaleSearch.IsChecked == false) { result = SearchDonor.SearchGenderFemale(); viewSerchGridDonors.ItemsSource = result; } // אם הוא מחפש רק את המספר סידורי textSearch = nameSearch.Text + addressSearch.Text + telSearch.Text + emailSearch.Text; if (string.IsNullOrEmpty(textSearch) && genderMaleSearch.IsChecked == false && genderFeamleSearch.IsChecked == false) { result = SearchDonor.SearchID(idsearch.Text); viewSerchGridDonors.ItemsSource = result; } //אם הוא מחפש רק את השם textSearch = idsearch.Text + addressSearch.Text + telSearch.Text + emailSearch.Text; if (string.IsNullOrEmpty(textSearch) && genderMaleSearch.IsChecked == false && genderFeamleSearch.IsChecked == false) { result = SearchDonor.SearchName(nameSearch.Text); viewSerchGridDonors.ItemsSource = result; } // if search only the address textSearch = nameSearch.Text + idsearch.Text + telSearch.Text + emailSearch.Text; if (string.IsNullOrEmpty(textSearch) && genderMaleSearch.IsChecked == false && genderFeamleSearch.IsChecked == false) { result = SearchDonor.SearchAddress(addressSearch.Text); viewSerchGridDonors.ItemsSource = result; } //search telefon textSearch = nameSearch.Text + idsearch.Text + addressSearch.Text + emailSearch.Text; if (string.IsNullOrEmpty(textSearch) && genderMaleSearch.IsChecked == false && genderFeamleSearch.IsChecked == false) { result = SearchDonor.SearchTelefon(telSearch.Text); viewSerchGridDonors.ItemsSource = result; } //search email textSearch = nameSearch.Text + idsearch.Text + addressSearch.Text + telSearch.Text; if (string.IsNullOrEmpty(textSearch) && genderFeamleSearch.IsChecked == false && genderMaleSearch.IsChecked == false) { result = SearchDonor.SearchEmail(emailSearch.Text); viewSerchGridDonors.ItemsSource = result; } } catch (Exception ex) { MessageBox.Show(ex.Message); } }
כמובן שזה רק ההתחלה.. כיון שצריך להוסיף מה קורה כאשר הוא מזין 2 פרמטרים (שם +כתובת וכדו'), ומה כשהוא מזין ב3 וכן על זה הדרך.
כמובן שזה ארוך כאורך הגלות לכתוב את כל האפשרויות שיכולות להיות (ועוד כל מה שכתבתי זה רק לגבי חיפוש לפי נתוני התורם, וצריך עוד לכתוב לגבי חיפוש לפי נתוני התרומה וכדו').
לכן שאלתי היא האם אפשר לכתוב מתודה גנרית שתדע לזהות מה אני מחפש ולפי זה לבחור היכן לחפש.. למשל לכל טקטסבוקס יש שם ע"פ הפרמטר שהוא אמור לקבל, האם אפשר שהמתודה תזהה לפי השם של הטקסטבוקס שנשלח אליה באיזה מאפיין מדובר (טלפון/כתובת/שם וכדו') וע"פ זה תדע לחפש במאפיין הנ"ל?
כמו"כ האם יש איזושהי דרך יותר פשוטה לכתוב את פונקציות החיפוש?
ניסיתי לכתוב בהתחלה את כל הפרמטרים יחד, אבל במקרה כזה אם הוא מכניס רק פרמטר אחד זה לא ייתן שום תוצאה.
לדוגמ' בקוד הבא:IEnumerable<Donor> result; result = from donor in AddTorem.donors where donor.Id == int.Parse(idsearch.Text) && (donor.FirstName == nameSearch.Text || donor.LastName == nameSearch.Text) && donor.Adress == addressSearch.Text select donor;
צריך להזין גם ID וגם שם וכתובת כדי לקבל תוצאה, ואם אחד מהם ריק הוא כותב לי "מחרוזת קלט לא הייתה בתבנית הנכונה"..
אשמח לשמוע עיצות ותובנות :lol: :lol:
תודה רבה רבה!!פורסם במקור בפורום CODE613 ב09/08/2015 01:25 (+03:00)
-
זאת בעיה ידועה ומוכרת, כבר הסברתי לך כמה פעמים, אין מסך מספיק גדול בעולם הזה בשביל להכיל את כל האפשרויות, וקל וחומר שאין משתמש שמוכן להתסבך כל כך. קשה מאוד להנגיש UI של משתמש פשוט, לנוסחאות קוד של SQL שאין להם סוף.
פורסם במקור בפורום CODE613 ב09/08/2015 13:17 (+03:00)
-
אין לי זמן לעבור על הכל, אך מלמעלה:
קודם כל לא ברורה לי הבחירה ב abstract class
פונקציה כללית לחיפוש יכולה להיראות כך:
public static IEnumerable<T> SearchString<T>(IEnumerable<T> lst, string sProperty, string sVal)
{MemberInfo mi = ((MemberInfo)typeof(T).GetField(sProperty) ?? (MemberInfo)typeof(T).GetProperty(sProperty)); if (mi == null) throw new ArgumentException("Field/Property does not exists", "sProperty"); if (mi.MemberType == MemberTypes.Property) { return lst.Where(d => (((PropertyInfo)mi).GetValue(d) ?? "").ToString().Contains(sVal)); } else { return lst.Where(d => (((FieldInfo)mi).GetValue(d) ?? "").ToString().Contains(sVal)); } }
פורסם במקור בפורום CODE613 ב09/08/2015 13:36 (+03:00)
-
אין לי זמן לעבור על הכל, אך מלמעלה:
קודם כל לא ברורה לי הבחירה ב abstract classבחרתי במחלקה אבסטרקטית כיון שאין לי שום מטרה לייצר אובייקטים ממנה, אלא רק לספק לי את השימוש במתודות החיפוש.
תודה על שתי התגובות שלך!! למדתי מזה הרבה דברים שלא הכרתי :lol: :lol:
לא הכרתי את האופרטור ?? וכמו כן לא הכרתי את המחלקה memberInfo.
זה בדיוק מה שחיפשתי איך לכתוב פונקציה גנרית לחיפוש!! תודה רבה!ארכיטקט לא הבנתי מה כוונתך? שאין צורך לתת למשתמש בUI את כל אפשרויות החיפוש? לבחור רק כמה אפשרויות יותר שימושיות ואותם לאפשר לו??
פורסם במקור בפורום CODE613 ב09/08/2015 15:50 (+03:00)
-
עשית קצת מישמש
מחלקה אבסטרקטית זה מחלקה שמיועדת לתאר קווים מנחים (ובדוטנט גם פונקציונליות) משותפים לאובייקטים שיירשו ממנה - קרי - מיועדת על מנת שיירשו ממנה ויממשו את המתודות במחלקה היורשת, היטיבו לתאר זאת בשפת VB שם מחלקה אבסטרקטית נקראת MustInherit . . .
אתה למעשה צריך כאן מחלקה סטטית, מחלקה סטטית היא מחלקה שאי אפשר ליצור ממנה אובייקטים והיא למעשה סוג של מחסן קוד, מה שאתה צריך כאן.
פורסם במקור בפורום CODE613 ב09/08/2015 16:20 (+03:00)
-
כאן העלתי דוגמא לקוד באקסס, שנ"ל קצר יותר.
כשבכל שדה בודק איזה סינון להחיל עליו.
כשבסוף מצרף את כל הסינוניםאני לא מבין VB וניסיתי להמיר אותו כאן אבל זה כתב שיש לו שגיאה ושהוא לא יכול להמיר את הקובץ
לא הבנתי אותך.. אתה בעצם מחפש לפי כל פרמטר בנפרד, ואח"כ מקבץ את כל התוצאות, ואז שוב מבצע סינון?? שהרי זה לא עוזר לי שיהיו לי את כל התוצאות שהרי אם הוא מזין נתונים בכמה מקומות אז הוא רוצה לסנן גם ע"פ הפרמטר הזה וגם הזה והזה.. אז בעצם מראש צריך להריץ שאילתא אחת שתסנן ע"פ כל הפרמטרים?? נמצא שצריך לכתוב שאילתא לכל שילוב אפשרי ולפי מה שהמשתמש מזין לדעת באיזה שאילתא לבחור..פורסם במקור בפורום CODE613 ב09/08/2015 18:25 (+03:00)
-
@HSF
כאן העלתי דוגמא לקוד באקסס, שנ"ל קצר יותר.כשבכל שדה בודק איזה סינון להחיל עליו.
כשבסוף מצרף את כל הסינוניםאני לא מבין VB וניסיתי להמיר אותו כאן אבל זה כתב שיש לו שגיאה ושהוא לא יכול להמיר את הקובץ
לא הבנתי אותך.. אתה בעצם מחפש לפי כל פרמטר בנפרד, ואח"כ מקבץ את כל התוצאות, ואז שוב מבצע סינון?? שהרי זה לא עוזר לי שיהיו לי את כל התוצאות שהרי אם הוא מזין נתונים בכמה מקומות אז הוא רוצה לסנן גם ע"פ הפרמטר הזה וגם הזה והזה.. אז בעצם מראש צריך להריץ שאילתא אחת שתסנן ע"פ כל הפרמטרים?? נמצא שצריך לכתוב שאילתא לכל שילוב אפשרי ולפי מה שהמשתמש מזין לדעת באיזה שאילתא לבחור..אני מכין מראש את נוסחת הסינון לכל פרמטר בנפרד, ומשתמש בפונקציית IF שאם לא בחר סינו יוסיף סינון "" ובמידה ובחר סינון אחר (כגון: שווה ל.. /החל מ /עד/בין/גדול/קטן, כל דבר לפי ענינו) מוסיף את הנוסחה למשתנה פנימי בהתאם לפרמטר שלו.
ולבסוף אני מאחד את כל הסינונים.ולדוגמא הסינון של סכום מאוחסן במשתנה X
הסינון של תאריך מאוחסן במשתנה XX
בסוף אני עושה איחוד של X & XX ומוסיף אותו לשורת הסינון בשאילתה
במידה ואין שום סינון הרי נוסף רק "" כאמור.פורסם במקור בפורום CODE613 ב09/08/2015 18:34 (+03:00)
-
קודם כל אתה מסנן רשימות ולא דטהבייס ויש הבדל גדול
לסינון מול דטהבייס יש כלים שיודעים לבנות לך שאילתה מכל הבלגאן הזהANYWAY מה שכתבת הוא קוד ספגטי קלאסי - דע לעתיד שאם קוד מגיע לכזו רמת סיבוכיות אז משהו בגישה שלך לא נכון (אקסס - יוצא מן הכלל)
לסינון רשימות אפשר לעשות סינון חוזר של אותה רשימה משהו כזה:
static void Main(string[] args) { List<Donor> dnrSource = new List<Donor>(); dnrSource.Add(new Donor { FirstName = "John", LastName = "Doe", Address = "31 Peachtree st."}); dnrSource.Add(new Donor { FirstName = "Jane", LastName = "Doe", Address = "31 Peachtree st." }); dnrSource.Add(new Donor { FirstName = "Jane", LastName = "Doe" }); List<Donor> dnrFiltered = new List<Donor>(dnrSource.ToArray()); if (!string.IsNullOrEmpty(FirstNameSearch.Text)) { dnrFiltered = new List<Donor>(SearchString(dnrFiltered, "FirstName", FirstNameSearch.Text)); } if (!string.IsNullOrEmpty(LastNamesearch.Text)) { dnrFiltered = new List<Donor>(SearchString(dnrFiltered, "LastName", LastNamesearch.Text)); } if (!string.IsNullOrEmpty(Addresssearch.Text)) { dnrFiltered = new List<Donor>(SearchString(dnrFiltered, "Address", Addresssearch.Text)); } }
פורסם במקור בפורום CODE613 ב09/08/2015 20:17 (+03:00)
-
ANYWAY מה שכתבת הוא קוד ספגטי קלאסי - דע לעתיד שאם קוד מגיע לכזו רמת סיבוכיות אז משהו בגישה שלך לא נכון (אקסס - יוצא מן הכלל)
בדיוק לכן שאלתי, כי זה היה נראה לי מוזר.. ארוך ומיותר..
יישבתי הרבה כדי ללמוד ולהבין את הקוד שכתבת..
לבסוף נפל לי האסימון למה התכוונתם (אתה וHSF)(בסוף הוא נופל :lol: :lol: )
בעצם אתם מריצים חיפוש של פרמטר אחד (לדוג' שם) ואז על הרשימה שהתקבלה אתם מריצים את החיפוש השני (לדוג' של הכתובת) ועל הרשימה המצומצמת שמתקבלת אתם מריצים את השלישי וכו'.
כך גם אתה פותר את הבעיה שהסתבכתי איתה לכתוב את כל הוריאציות של הצירופים האפשריים, אלא אתה עושה IF כמספר התיבות טקסט, ואם המשתמש הזין טקסט אתה מריץ חיפוש על הרשימה שהתקבלה מהחיפוש הקודם.
כ"כ פשוט!! איך לא חשבתי על זה :shock: ישבתי הרבה זמן לכתוב את הקוד הזה (שהוא הרבה יותר ארוך ממה שהבאתי כאן.. מה שעשיתי כאן זה היה רק בשביל חיפוש של פרמטר אחד..)
תודה רבה רבה שהארתם את עיני!!!פורסם במקור בפורום CODE613 ב09/08/2015 22:43 (+03:00)
-
פונקציה כללית לחיפוש יכולה להיראות כך:
public static IEnumerable<T> SearchString<T>(IEnumerable<T> lst, string sProperty, string sVal)
{MemberInfo mi = ((MemberInfo)typeof(T).GetField(sProperty) ?? (MemberInfo)typeof(T).GetProperty(sProperty)); if (mi == null) throw new ArgumentException("Field/Property does not exists", "sProperty"); if (mi.MemberType == MemberTypes.Property) { return lst.Where(d => (((PropertyInfo)mi).GetValue(d) ?? "").ToString().Contains(sVal)); } else { return lst.Where(d => (((FieldInfo)mi).GetValue(d) ?? "").ToString().Contains(sVal)); } }
הפונקציה הזו טובה כשהערך הוא string
ניסיתי לכתוב מתודה גנרית דומה שיכולה לחפש כשהמאפיין הוא מסוג double או int (כיון שעם הפונקציה הזאת הוא זרק לי חריג שהערך אינו מתאים).
לא הצלחתי..
ניסיתי לכתוב בתוך הcontains (double.parse) ואז את הערך.. אבל זה לא הצליח כיון שלפני זה יש Tostring ניסיתי למחוק את זה אבל אז הוא לא נותן לי את הcontains.. בקיצור - הסתבכתי
אשמח לשמוע מה לעשות...
וגם מדוע בכלל אתה צריך את הtostring הזה?
תודה רבה!!פורסם במקור בפורום CODE613 ב10/08/2015 23:20 (+03:00)
-
למה צריך את ה ToString? כי GetValue מחזיר object כי הוא לא יודע מה סוג ה property ואי אפשר להשוות object ל string בלי ToString
פונקציה כללית:public static IEnumerable<T> Search<T>(IEnumerable<T> lst, string sProperty, dynamic Val, bool contains = false) { MemberInfo mi = ((MemberInfo)typeof(T).GetField(sProperty) ?? (MemberInfo)typeof(T).GetProperty(sProperty)); if (mi == null) throw new ArgumentException("Field/Property does not exists", "sProperty"); if (mi.MemberType == MemberTypes.Property) { PropertyInfo pi = (PropertyInfo)mi; return lst.Where(d => Match((pi.GetValue(d) ?? "").ToString(), Val.ToString(), contains)); } else { FieldInfo fi = (FieldInfo)mi; return lst.Where(d => Match((fi.GetValue(d) ?? "").ToString(), Val.ToString(), contains)); } } public static bool Match(string sLeft,string sRight, bool contains) { return (sLeft == sRight || (contains && sLeft.Contains(sRight))); }
פורסם במקור בפורום CODE613 ב11/08/2015 13:47 (+03:00)
-
return lst.Where(d => Match((pi.GetValue(d) ?? "").ToString(), Val.ToString(), contains public static bool Match(string sLeft,string sRight, bool contains) { return (sLeft == sRight || (contains && sLeft.Contains(sRight))); }
אשמח אם תוכל להסביר לי מה בעצם אתה עושה ב2 השורות הללו?
תודה רבה רבה!! כנראה שיש לי עוד הרבה פערים להשלים :lol: :lol:פורסם במקור בפורום CODE613 ב11/08/2015 16:08 (+03:00)
-
תודה רבה soft על כל העזרה עם הפונקציות!!דרך זה למדתי על עולם שלם שלא כ"כ הכרתי..
(על כל ספריית הReflection "שיקוף" בלע"ז :lol: )
לאט לאט אני מגלה עולם..
ובכל אופן זו הייתה טעות שלי.. הפונקציה הראשונה עובדת טוב גם על מאפיינים של INT וDOUBLE, הייתה לי שגיאה אחרת שבגללה הוא זרק לי את החריג שהערך אינו מתאים
בכל אופן תיקנתי אותה.. ועכשיו הכל רץ חלק!! (גם אם אני משתמש בפונקציה הראשונה וגם אם בשניה..)פורסם במקור בפורום CODE613 ב11/08/2015 20:04 (+03:00)