מידע על הConnection

כלליים

New member
מידע על הConnection

שלום ושבוע טוב.

בניתי מערכת מידע, שצד השרת שלה הוא SQL SERVER, וצד הלקוח הוא אקסס.
בDB, יש טבלת Users, עם שמות משתמשים וסיסמאות. הפעולה הראשונה שנעשית בהפעלת האפליקציה, היא לבקש מהמשתמש שם וסיסמא, ולאמת מול טבלת הUSERS.

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

האם לאחר שמשתמש הזין שם וסיסמא, אני יכול לשלוח מידע לשרת שיגדיר UserName לכל Connection, ואחר-כך כשהרשומה נערכת, ללכוד מי ערך אותה לפי הConnection ששלח את פקודת העדכון?

תודה מכל הלב
 

כלליים

New member
הוא איננו קשור

הקישור הנ"ל, מתייחס לConnections לאקסס.
אני צריך דבר אחר: לשלוח מידע מצד הלקוח, אל שרת הSQL, שיקושר אל הConnection, והשרת יידע להשתמש במידע הזה בכל Update שהConnection מבצע.
 

pitoach

New member
אתה יכול לדעת בדיוק איזה משתמש הריץ כל שאילתה

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

1. אתה יכול לקבוע להריץ כל פעולה על ידי משתמש מסויים על ידי Impersonation
http://msdn.microsoft.com/en-us/library/ms181362.aspx

2. אתה יכול למצוא איזה משתמש הריץ שאילתה מסויימת תוך כדי שהוא עדיין מחובר על ידי שימוש בפונקציות מובנות ואז בטריגר אתה יכול לעשות עם האינפורמציה מה שאתה רוצה
http://blog.sqlauthority.com/2007/10/27/sql-server-2005-get-current-user-get-logged-in-user/

3. אתה יכול לנטר פעולות בעזרת Extended Events כולל משתמשים שמריצים שאילתה מסויימת או כמעט כל דבר אחר ואז לפעול בהתאם לניטור (ניטור און-ליין)
http://www.sqlteam.com/article/advanced-sql-server-2008-extended-events-with-examples

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

כלליים

New member
אחדד את שאלתי

באופן אחר:
נניח, שיש לי אפליקצית C#.
באפליקציה יש טפסים שונים, שחלקם מציגים מידע משרת SQL SERVER.
כמובן, שהאפליקציה מריצה שאילתות DML: משנה רשומות, מוסיפה וכו'.

מבחינתי, כל הפעלה של האפליקציה, היא session.
למרות שאני משער שמבחינת השרת זה לא כך.

יש כמה טבלאות חשובות, שיש בהם שדה SessionUpdater, שם אני אמור לעדכן איזו הפעלה ערכה/הוסיפה את הרשומה.
אני זקוק, שכל הרצה של DML, תעדכן את השדה UpdaterSession.
כמובן, הדרך הפשוטה היא להוסיף לכל INSERT ןUPDATE עוד קוד רלוונטי.
החסרון: מכיוון שיש לי מספר גדול של הרצות DML, זה מעצבן לזכור תמיד לעדכן גם את הSession.

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

אני מקווה שהפעם אני מובן יותר.
 

pitoach

New member
הנה כיוון שיכול לעזור לאפיון כזה למשל

* החלק שלי מופיע עם כוכביות ושלך עם מקף-

- מבחינתי, כל הפעלה של האפליקציה, היא session.
למרות שאני משער שמבחינת השרת זה לא כך.
* בכל הפעלה של אפליקציה מתקיים אירוע מובנה בשם Application_Start. ניתן לייצר Guid חדש בכל ה]פעלה של האפליקציה ולהעביר אותו למסד הנתונים כפרמטר בשרשרת ההתחברות (או פחות טוב אבל מחייב פחות ידע פשוט בשאילתה בתכניס אותו למסד הנתונים)
יצירת Guid מבצעים על ידי:
Guid id = Guid.NewGuid();
תוכלך לקרוא מעט יותר על אירועים מובנים שיש לאפליקציה כאן:
http://blog.ie-soft.de/post/2007/12/globalasax-events.aspx
עתה אחרי שיש לך את הנתון בשרשרת ההתחברות אתה יכול תמיד לגשת אליו בכל נקודת זמן.

- יש כמה טבלאות חשובות, שיש בהם שדה SessionUpdater, שם אני אמור לעדכן איזו הפעלה ערכה/הוסיפה את הרשומה.
אני זקוק, שכל הרצה של DML, תעדכן את השדה UpdaterSession.
כמובן, הדרך הפשוטה היא להוסיף לכל INSERT ןUPDATE עוד קוד רלוונטי.
החסרון: מכיוון שיש לי מספר גדול של הרצות DML, זה מעצבן לזכור תמיד לעדכן גם את הSession.
* כאמור הפתרון המתאים הוא להעביר את הנתון כפרמטר בשרשרת ההתחברות. תוכל לראות דוגמה מעשית כאןף
http://stackoverflow.com/questions/...-if-i-use-connection-class-in-a-separate-file

- השאלה, האם יש פתרון בצד השרת לכך?
* תמיד התשובה לשדאלה האם אפשר היא כן זה אפשרי! לכל דבר יש פתרון


- למשל: האם אפשר, אולי באמצעות הConnectionString, להעביר איזה מידע לשרת?
מידע שאפשר יהיה ללכוד באמצעות טריגר, וכך לעדכן בצורה נקיה וחלקה?
* ראה דוגמה למעשה
 

כלליים

New member
לא הבנתי כ"כ

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

אבל זה לא פותר את הבעיה:
איך אני מוודא שכל שאילתה תרוץ תחת שם משתמש ספציפי?

בסוף עשיתי כך:
השתמשתי ברכיב APP של הConnectionString, כדי להעביר את המידע הדרוש.
למשל: APP=Yosi.
ובשרת, הוספתי טריגר על כל הטבלאות, שבכל שינוי והוספה של רשומה, מעדכן את השדה LastEditor:
SET LastEditor = APP_NAME()


אם דרך נכונה יותר, אשמח לדעת.
 

pitoach

New member
הקישור מכיל גם הוספת פרמטרים לשרשרת ההתחברות

ראה את החלק שדן ב
Parameters.Add(param);
* עם זה אתה יכול גם לעשות שימוש בדרך שבחרת מבחינת שימוש בשם האפליקציה (נראה לי מעט מוזר לשנות פרמטרים של אפליקציה עבור ההתחברות, וזה יכול ליצור בעיה לא קטנה כאשר יהיו משתמשים שיעבדו במקביל והתוצאה עלולה להתערבב אם לא תנהל נעילות בצורה מאוד מאוד זהירה... אבל אם זה מתאים לך זה גם דרך)

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

אני מציע לבדוק אפשרות לשלוט על הדברים פשוט ברמת האפליקציה (למשל בשאילתה להוסיף את עדכון השדה ולא בטריגר להפעיל שאילתה נוספת).

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

** בדרך כלל במחשבים אין דרך "נכונה" כאשר מדברים על 2 דרכים שמביאות אותנו לתוצאה הרצויה בצורה טובה
. רק האפיון קובע את הדרך המתאימה (במקרה אחר הדרך הקודמת עלולה להיות המתאימה ולכן ה"נכונה"). זמן פיתוח הרבה פעמים הוא גורם מכריע על בחירת הדרך ולא רק התוצאה.
 

כלליים

New member
תודה על ההסברים

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

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

ושוב:
 

pitoach

New member
הבהרה לנקודה ראשונה והמשך נקודה שנייה->

1. הוספת פרמטרים לשרשרת ההתחברות אינה זהה לשינוי השם של האפליקציה. APP_NAME הוא פרמטר מובנה בודד ומשותף לכל האפליקציה ולא רק לשרשרת ההתחברות. שינוי כזה הוא שינוי של האפליקציה עצמה בעטוד הוספת פרמטר לשרשרת ההתחברות יכול להיות דינאמי יותר ולאפשר עבודה מקבילה של כמה התחברויות עם כמה נתונים שונים בפרמטר שמוסיפים (APP_NAME הוא פרמטר משותף מכיוון שהוא ברמת האפליקציה ולכן זה מקור לבעיות כפי שכתבתי מעל)

2. הפתרון יכול להיות כמו שכתבתי לעבוד עם SP שיושב במסד הנתונים. מבחינת המפתח הוא קופסא שחורה כמו טריגר ובעצם האפליקציה מריצה את ה SP אבל ה SP מריץ במכה אחת גם את מה שרצית להפריד לטריגר. לכן החופש נשאר כשהיה. במקרה הכי קיצוני ניתן גם לבנות שאילתה דינאמית ב SP ולא רק שאיחלתה קבועה אם ה DDL משתנה (מבנה האובייקטים)

* יכול להיות שהתכוונת ל DDL ולא DML
?
DML זה החלק של הנתונים עצמם ו DDL הוא החלק של המבנה אלמנטים (אם ה DDL קבוע הדברים תמיד יותר קלים כי אין צורך בגמישות והשאילתות קבועות)
 

כלליים

New member
מה לא טוב בDML?

יש לי באפליקציה 50 פקודות UPDATE ו20 פקודות INSERT.
במקום לטפל בכל פעם בנפרד בשדות EditorNAme [שם המשתמש שערך את הרשומה] וDeitDate [מועד העריכה],
השתמשתי בטריגר פשוט מאד [צילום מסך מצורף]
 

pitoach

New member
היה עדיף פשוט מבחינת ביצועים במקום לעבוד עם

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


** העשרה

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

במקום APP_NAME ניתן היה לעבוד גם עם נתון מובנה של connection_id שהוא ערך ייחודי שכל CONNECTION מקבל.

בדוק את ה DMV הבא מעט dm_exec_connections ואת השאילתה הבאה
select connection_id FROM sys.dm_exec_connections

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