משום מה השאלה הזאת נשאלת שוב ושוב בפורומים...
לשמור זה די ברור איך, אני יוצר פקודת sql עם פרמטרים, או stored procedure ,ומעביר אליה את הבתים של התמונה, כמובן שהעמודה בדטה בייס צריכה להיות מסוג image/binary.
לדוגמה:
byte[] imagedata = null;
//now we can get the image bytes with filestream on local system, or from FileUpload on our web page
System.Data.SqlClient.SqlConnection con=new System.Data.SqlClient.SqlConnection("myconstring");
System.Data.SqlClient.SqlCommand com = new System.Data.SqlClient.SqlCommand("insert into images (imagename,imagedata) values (@imagename,@imagedata)", con);
com.Parameters.Add(new System.Data.SqlClient.SqlParameter("@imagename", "myimage.gif"));
com.Parameters.Add(new System.Data.SqlClient.SqlParameter("@imagedata", imagedata));
con.Open();
com.ExecuteNonQuery();
יופי, איך מושכים, כרגיל, פקודת select רגילה כשמה שאנו מקבלים מהעמודה הזאת היא מערך של בתים עם נתוני התמונה.
עכשיו כדי להציג אותה ללקוח יש כמה שיטות. קודם כל ניתן להפוך את מערך הבתים לאובייקט של BitMap
byte[] b=null;//
MemoryStream ms=new MemoryStream(b);
System.Drawing.Bitmap bm = new System.Drawing.Bitmap(ms);
או אם יש לי באתר דף שאמור להציג תמונות מדטה בייס לפי איזה פרמטר שהוא מקבל נשתמש ב Response.BinaryWrite כדי לכתוב את מערך הבתים. בדף הרגיל שבו מוצג הטקסט והתמונות נשים כתובת של תמונה עם כתובת של דף אחר, ובדף האחר נשתמש בפונקציה הזאת כדי לשלוח את הבתים בתור תמונה
נניח שיש לי דף PictureGallery.aspx
בתוך הדף אני רוצה להציג תמונות שימשכו מהדטה בייס. אני יוצר דף מיוחד שכל תפקידו הוא למשוך תמונה מהדטה בייס ולשלוח אותה ללקוח, נקרא לו PictureView.aspx
בדף PictureGallery.aspx אני שם לינקים לדף PictureView.aspx בתור כתובת של תמונה:
<img src="PictureView.aspx?imgid=34"/>
וככה מוסיף תמונות כמה שארצה. כעת בדף PictureView.aspx הקוד יראה משהו כמו:
byte[] b = (byte[])com.ExecuteScalar("select imagedata from myimages where imageid=" + Request.Params["imgid"]);
Response.ContentType = "image/jpeg";
Response.BinaryWrite(b);
Response.End();
Technorati Tags:
Sql,
SqlParameter
Be the first to rate this post
- Currently 0/5 Stars.
- 1
- 2
- 3
- 4
- 5
הזכרנו מספר פעמים את היתרון של stored procedures מנקודת אבטחת מידע. אולם אחת הבעיות שיש ב stored procedures היא שיש נתונים שלא ניתן להעביר כפרמטר, לדוגמה, העמודה לפיה ממיינים. נניח שיש לי דף שניתן למיון לפי מספר עמודות, לא ניתן להעביר ל stored procedure את שם העמודה למיון בצורה הבאה:
create procedure temp1
@sortName varchar(20)
as
begin
select * from article order by @sortName
end
אז מה כן עושים אם אנו עדיין רוצים להמשיך להשתמש ב stored procedures וגם לאפשר מיונים לפי שדות שונים?
אז צריך קצת להתחכם, וגם לסרבל, אבל עדיין נראה לי שזה שווה את זה...
נניח שיש לי 2 עמודות שניתן למיין לפיהן, וגם ניתן למיין בסדר עולה או יורד. אז נכון שתמיד ניתן להשתמש ב sp_executesql , אבל אז הלכה כל התועלת של שימוש ב stored procedure... מישהו פעם הציע לי לבנות 4 stored procedures... כמובן שזה לא סביר... אבל נעשה משהו די דומה:)
create procedure temp1
@sortName varchar(20),
@sortDirection varchar(4)='asc'
as
begin
select * from article order by
case WHEN @sortName = 'article_id' and @sortDirection='asc' THEN article_id end asc,
case WHEN @sortName = 'article_id' and @sortDirection='desc' THEN article_id end desc,
case WHEN @sortName = 'publish_date' and @sortDirection='asc' THEN publish_date end asc,
case WHEN @sortName = 'publish_date' and @sortDirection='desc' THEN publish_date end desc
end
Be the first to rate this post
- Currently 0/5 Stars.
- 1
- 2
- 3
- 4
- 5
Technorati Tags:
sql,
paging
לעיתים אנו רוצים להציג למשתמשים מידע רב מבסיס הנתונים, ולא רוצים להציג את כולו בדף אחד. אז נכון שקיימים הפקדים של הדוט נט שחלקם מכילים כבר אופציה לדיפדוף, אבל זה בעצם דיפדוף "מדומה", הם לא באמת מושכים את המידע שאנחנו צריכים מהדטה בייס, הם מושכים את כל הרשומות, ומציגים לנו את מה שאנחנו צריכים, לכן, אם יש לי מיליון רשומות ואני רוצה להציג 50 כל פעם, אזי כל פעם שאני מדפדף דרך הקונטרול, הוא מושך את כל המיליון רשומות מהדטה בייס ופשוט מציג את ה 50 הבאות. אז השיטה הזו טובה כשרוצים בזריזות לבנות איזה דף עם כמה נתונים, אבל לשרת אמיתי שמשרת עשרות אלפי לקוחות צריך למצוא שיטה טובה יותר.
הכתבה תתרכז בצד של השאילתות לדטה בייס ולא בצד הלקוח. בפעם הבאה נדבר על ישום אג`קסי של הדפדוף ואז גם ניתן יהיה להוריד את הפרוייקט.
השיטה הקלה, אם נתמזל מזלנו ואנחנו לא צריכים אפשרות למיין, או מאפשרים מיון רק לפי עמודה שהיא ייחודית כמו אינדקס, אז פשוט נבנה את הדיפדוף כך שימשוך כל פעם את מספר הרשומות שאנחנו רוצים עם תנאי שמספר האינדקס יהיה גדול (או קטן במקרה של מיון מהגדול לקטן) ממספר כלשהו - האינדקס האחרון מהדף הקודם ( שאותו נשמור בדף או בסשן ). לדוגמא:
ניצור טבלה בשם t1 עם 3 עמודות:
מספר השורות שאנחנו רוצים להציג בדף
const int rowsPerPage=2;
משתנה שמכיל את מספר המזהה של השורה האחרונה שמשכנו (בפעם הראשונה הוא יהיה 0 כמובן):
int lastid=0;
השאילתה :
sql:Sel ect top [rowsPerPage] from t1 where id>[lastid] order by id
MySql : Sel ect * from t1 where id>[lastid] order by id limit [rowsPerPage]
כעת נשמור לנו את המספר המזהה של הרשומה האחרונה שמשכנו -3 את המספר כאמור ניתן לשמור או בסשן (לא מומלץ) או בדף עצמו - למשל בלחצן שמעביר לדף הבא - להוסיף לו את הפרמטר הזה.
כשהלקוח ילחץ על דיפדוף לדף הבא או הקודם, נקבל בשרת את הערך הזה ולפיו נדע איזה רשומות למשוך עכשיו. במקרה שלנו נקבל את המספר 3 לשרת והשאילתה תהיה:
Sql :Sel ect top 2 * from t1 where id>3 order by id
MySql: Sel ect * from t1 where id>3 order by id limit 2
וכך הלאה לשאר הדפים.
החסרונות ברורים:
לא ניתן למיין לפי עמודות אחרות שכן אנחנו חייבים עמודה עם מזהה יחודי
לא ניתן לקפוץ לעמוד מסויים, שכן אנחנו יודעים את האינדקס של העמוד הבא והקודם בלבד
כדי לנסות לפתור את 2 המגבלות האלה, ניתן לשכלל קצת את הפיתרון שלנו כפי שמופיע באתר של מיקרוסופט
בשיטה זו נוכל גם למיין לפי עמודות אחרות וגם נוכל לקפוץ לכל עמוד שנרצה:
נגדיר משתנה שישמור את מספר הדף:
int pageNum=1;
Sql : select top [rowsPerPage] * from (select top [rowsPerPage*pageNum] * from t1 order by name desc) as t2 order by name
Mysql : select * from (select * from t1 order by name desc limit [rowsPerPage*pageNum]) as t2 order by name limit [rowsPerPage]
דבר נוסף שחסכנו זה את הצורך לשמור את האינדקס של העמודה האחרונה, אנחנו ישר בוחרים לפי מספר הדף שהלקוח לחץ עליו. נניח שהוא לחץ על דף מספר 3, ואנו כאמור רוצים להציג 2 שורות בכל דף, אזי השאילתה תהיה :
MySql : sel ect * from (SEL ECT * FROM t1 order by name desc limit 6) as t2 order by name limit 2
Sql :sel ect top 2* from( sel ect top 6 * from t1 order by name desc) as t2 order by name
אולם גם זה פיתרון חלקי ( מיקרוסופט כנראה לא שמה לב...) , כי עבור עמודות עם ערכים זהים, כמו עמודת "מין", תתקבלנה תוצאות מוזרות :
MySql : sel ect * from (SEL ECT * FROM t1 order by gender desc limit 6) as t2 order by gender limit 2
Sql : sel ect top 2 * from (sel ect top 6 from t1 order by gender desc) as t2 order by gender
עדיין אנחנו לא יכולים למיין לפי עמודת "מין"...
אז מה כן עושים? טוב, אז אם יש לנו Sql Server 2005 או MySql הפיתרון יעיל וקל. לא משנה לפי איזו עמודה אני רוצה למיין:
ב sql server 2005 נכתוב
select * ,rank from (select *, row_number() over(order by gender desc) as rank from t1) as t2 where rank between [(pageNum-1)*rowsPerPage+1] and [(pageNum-1)*rowsPerPage+rowsPerPage]
וב MySql הרבה יותר פשוט, פשוט נכתוב
select * from clients limit [(pageNum-1)*rowsPerPage],[rowsPerPage]
והתוצאה כצפוי:
MySql : sel ect * from t1 order by gender limit 2,2
Sql : sel ect *,rank from
(sel ect *,row_number() over(order by gender desc) as rank from t1 ) as t2
where rank between 7 and 8
אבל מה עושים אם אני עובד עם שרת אחר?
אז הפיתרון קצת יותר איטי ויותר מסובך, אבל עדיין יותר יעיל מלמשוך את כל הרשומות אלי לדף...
כל פעם אני רוצה לבצע שאילתה, אני אצור טבלה זמנית, עם עמודה אחת של מיספור אוטומטי ועמודה נוספת שתשמור את מספר האינדקס מהטבלה הראשית.
Create table temp1 (tid int not null primary key auto_increment/identity,foreign_id int)
* אם אני לא סוגר את החיבור לדטה בייס במהלך הפונקציה אז ניתן ליצור את הטבלה בתור טבלה זמנית ואז היא תימחק אוטומטית בעת סגירת החיבור- יותר מהיר ויותר נקי....
כעת נעביר לטבלה הזאת את מספרי האינדקס מהטבלה המקורית, כשהם כבר ממויינים לפי העמודה שאני רוצה:
Insert into temp1 (foreign_id) select id from t1 order by gender
וכעת אני יכול לבחור את מספרי השורות שאני רוצה:
Select * from t1, temp1 where t1.id=temp1.foreign_id and temp1.tid between [(pageNumber-1)*rowsPerPage+1] and [(pageNumber-1)* rowsPerPage+rowsPerPage]
והתוצאה כצפוי:
sel ect t1.* from temp1,t1 where t1.id=temp1.foreign_id and temp1.tid between ((2-1)*2+1) and ((2-1)*2+2) order by gender
רק לא לשכוח בסוף למחוק את הטבלה אם לא השתמשנו בטבלה זמנית...
* יש דרך לשיפור המהירות של השיטה האחרונה באתר 4guysfromrolla
* ניתן להשתמש ב stored procedures ליעול המהירות
Be the first to rate this post
- Currently 0/5 Stars.
- 1
- 2
- 3
- 4
- 5