PDA

View Full Version : سوال: نمایش تصاویر در GridView فقط در یک ارتباط با دیتابیس و نه چند ارتباط



RoostaYeBekr
یک شنبه 19 آبان 1387, 14:48 عصر
با سلام
همانطور که می دانیم روش معمول برای اینکه عکس ها در GridView نشان داده شود ، استفاده از کدهای زیر است ( کدهایی که من در ایبوک پیدا کردم و دیده ام که بقیه هم معمولا همین پیشنهاد را دارند ) . ( البته برنامه ی کاملش را هم فرستاده ام ، دیتابیس را از پوشه ی APP_Data بردارید ) :
به نظر من ، این کدهای پیشنهادی یک مشکل اساسی دارد و آن اینکه برای هر عکس ، می خواهد یک ارتباط با دیتابیس بزند . این اصلا صحیح نیست . ما باید کاری کنیم که بار روی دیتابیس کمتر شود . مثلا باید کاری می کردیم که در یک ارتباط تمام عکس ها را در یک DataTable بریزد و برنامه برای نمایش عکس ها از همین DataTable استفاده کند و دیگر هیچ ارتباطی با دیتابیس زده نشود ( چون قبلا تمام عکس ها را گرفته ). می خواستم بپرسم کسی برای رفع این مشکل راه حلی ندارد؟


<%@ WebHandler Language="C#" Class="ImageFromDB" %>
using System;
using System.Web;
public class ImageFromDB : IHttpHandler {

public void ProcessRequest (HttpContext context) {
string connectionString =
System.Configuration.ConfigurationManager.Connecti onStrings["My_DBConnectionString"].ConnectionString;
// Get the ID for this request.
string id = context.Request.QueryString["_id"];
if (id == null) throw new ApplicationException("Must specify ID.");
// Create a parameterized command for this record.
System.Data.SqlClient.SqlConnection con = new System.Data.SqlClient.SqlConnection(connectionStri ng);
string SQL = "SELECT _image FROM Table_image WHERE _id=@ID";
System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand(SQL, con);
cmd.Parameters.AddWithValue("@ID", id);
try
{
con.Open();
System.Data.SqlClient.SqlDataReader r =
cmd.ExecuteReader(System.Data.CommandBehavior.Sequ entialAccess);
if (r.Read())
{
int bufferSize = 100; // Size of the buffer.
byte[] bytes = new byte[bufferSize]; // The buffer.
long bytesRead; // The # of bytes read.
long readFrom = 0; // The starting index.
// Read the field 100 bytes at a time.
do
{
bytesRead = r.GetBytes(0, readFrom, bytes, 0, bufferSize);
context.Response.BinaryWrite(bytes);
readFrom += bufferSize;
} while (bytesRead == bufferSize);
}
r.Close();
}
finally
{
con.Close();
}
}

public bool IsReusable {
get {
return false;
}
}
}

RoostaYeBekr
سه شنبه 21 آبان 1387, 13:55 عصر
سلام
چرا هیچ کس جوابی به این سوال نمی دهد؟
:گریه:
:گریه:
:گریه:

RoostaYeBekr
سه شنبه 21 آبان 1387, 16:24 عصر
دوست عزیز من که از سوال شما چیزی نفهمیدم و حتما هم کسی تا به حال گیزی دست گیرش نشده ه پاسخ نداده.

منظورت از یک ارتباط و نه چند ارتباط چیه و اصلا سوالت مفهوم نیست . اگر میشه درست بگید تا بشه راهنمایی کرد
سلام
من تا الان که دوباره به این سوال مراجعه کردم ، دیدم که هیچ کس آن فایلی را که فرستادم ، دانلود نکرده . شاید اگر دانلود می کردید ، منظورم را متوجه می شدید.

در پروژه های ویندوزی ، در یک ارتباط تمام عکس ها را از دیتابیس می گیرند و در یک DataTable می ریزند . بعد هم آن DataTable را به عنصر نمایش دهنده مثلا DataGridView بایند می کنند. اگر همین کار را در پروژه ی وب با GridView بخواهیم انجام دهیم ، عکس ها نمایش داده نمی شوند. به خاطر همین توی ایبوک ها ، کدهایی را که در بالا فرستادم ، را برای انجام این کار ارائه می دهند. کدهایی که در بالا هست ، کاملا مشخص است که برای گرفتن هر عکس ، یک ارتباط با دیتابیس می زند . یعنی:
اگر دوتا عکس داشته باشیم ، دو تا ارتباط با دیتابیس می زند.
اگر چهل تا عکس داشته باشیم ، چهل تا ارتباط با دیتابیس می زند.
که این آخری خیلی بد است.
راستش نمی دانم دیگر چطور منظورم را بگویم . به هر حال اگر کسی باز هم منظورم را متوجه نشد ، فایلی که در بالا فرستادم دانلود کند. لازم هم نیست که فایل را اجرا کند . چون مفهوم حرفم ، با دیدن کدها ، کاملا مشخص است.

Chabok
سه شنبه 21 آبان 1387, 17:05 عصر
با سلام

به نکته بسیار خوبی اشاره فرمودین که نباید برای هر عکس سراغ دیتابیس رفت .

ولی چون شما خود عکس رو در دیتابیس ذخیره کردین ظاهرا چاره ای نیست .
چون که هندلر بر اساس کوئری استرینگ صدا زده میشه و خوب همین روشی میشه که استفاده کردین .

چاره این کار اینه که این هندلر شما اون دیتاسورسی رو که یک بار از دیتا پرشده رو در اختیار داشته باشه و بر اساس هر درخواست به اون دیتاسورس مراجعه کنه و از اونجا عکس رو بخونه .

شاید مثلا هنگام پر کردن دیتاسورس باید اون رو توسط Cache در حافظه Application-State قرار بدین تا اون هندلر هم بهش دسترسی داشته باشه و به جای خوندن از دیتابیس بر اساس این Id پاس داده شده از اون دیتاسورسی که در حافظه سمت اپلیکیشن هست فیلد رو بخونه و ارسال کنه .

این چیزی است که فعلا به ذهن من میرسه .

موفق باشید . خدانگهدار

ali_sorouri2005
سه شنبه 21 آبان 1387, 17:14 عصر
چه اجياريه كه عكس ها رو توي ديتابيس بزارين؟
خوب آدرسشو فقط تو ديتابيس بزار.
مشكلي داره اين كار با كاري كه شما مي خواي انجام بدي؟

Chabok
سه شنبه 21 آبان 1387, 17:39 عصر
سلام


چه اجياريه كه عكس ها رو توي ديتابيس بزارين؟
خوب آدرسشو فقط تو ديتابيس بزار.
مشكلي داره اين كار با كاري كه شما مي خواي انجام بدي؟
به هر حال شرایط کار هر کسی متفاوته و حتی اگه لزوم نباشه که توی دیتابیس ذخیره بشه این بحث خوش یکی از اون مباحثی است که آقای مداح اون رو به چالش کشیدن مسائل میدونن . پس بهتره صورت مسئله رو پاک نکنیم .


متئجه نمیشم شما اگر یک کانکشن بسازید و یک بار open کنی execute کنی و دیتا سورس رو بایند کنی اگر 40 رکورد جدول داشته باشه 40 بار کانکشن رو باز و بسته می کنه؟؟؟؟؟؟
بله . چون HttpHandler هر بار یک id دریافت می کند و با خواندن عکس متناظر ، آن را از طریق Response به کلاینت ارسال می کند .


شاید من نمی فهمم که شما درباره چه ایرادی از دات نت صحبت می کنید.
اسلام به ذات خود ندارد عیبی / هر عیب که هست از مسلمانی ماست :چشمک:


من با ریپیتر کار می کنم و اصلا توی لود مشکلی ندارم و در ضمن view state رو هم false کرده ام.
ربطی به این مسئله نداره .

موفق باشید . یا حق

RoostaYeBekr
سه شنبه 21 آبان 1387, 18:25 عصر
چه اجياريه كه عكس ها رو توي ديتابيس بزارين؟
خوب آدرسشو فقط تو ديتابيس بزار.
مشكلي داره اين كار با كاري كه شما مي خواي انجام بدي؟
با سلام و تشکر از همه ی کسانی که تا الان راهنمایی کردند

من قبلا این کاری را که شما گفته اید ، انجام داده ام. ولی به نظرم مشکلات زیادی دارد:

1 - زمانی که می خواهیم بک آپ بگیریم ، مجبوریم از دو چیز بگیریم : دیتابیس و پوشه ی تصاویر
2 - معمولا این خودمان نیستیم که بک آپ می گیریم . کسانی هستند که برنامه ی ما را روی سرور گذاشته اند و خیلی وقت ها یادشان می رود که باید علاوه بر دیتابیس ، از پوشه ی تصاویر هم بک آپ بگیرند . ( من خیلی وقت ها با این مشکل برخورد کرده ام)
3 - اگر تصاویر زیاد شود ، بک آپ گیری از آنها بسیار زمانبر خواهد بود ( من قبلا با این مشکل هم برخورد کرده ام)
4- اگر تصاویر هم در دیتابیس باشد ، قطعا اطلاعات ما یکپارچه تر است.

Alireza_Salehi
سه شنبه 21 آبان 1387, 19:46 عصر
با سلام و تشکر از همه ی کسانی که تا الان راهنمایی کردند

من قبلا این کاری را که شما گفته اید ، انجام داده ام. ولی به نظرم مشکلات زیادی دارد:

1 - زمانی که می خواهیم بک آپ بگیریم ، مجبوریم از دو چیز بگیریم : دیتابیس و پوشه ی تصاویر
2 - معمولا این خودمان نیستیم که بک آپ می گیریم . کسانی هستند که برنامه ی ما را روی سرور گذاشته اند و خیلی وقت ها یادشان می رود که باید علاوه بر دیتابیس ، از پوشه ی تصاویر هم بک آپ بگیرند . ( من خیلی وقت ها با این مشکل برخورد کرده ام)
3 - اگر تصاویر زیاد شود ، بک آپ گیری از آنها بسیار زمانبر خواهد بود ( من قبلا با این مشکل هم برخورد کرده ام)
4- اگر تصاویر هم در دیتابیس باشد ، قطعا اطلاعات ما یکپارچه تر است.


1. اگر کل تصاویر در یک پوشه باشند بک آپ گیری در دو مرحله خلاصه میشه: دیتابیس و فایل ها، اتوماتیک کردن این دو به صورت پشت سر هم کاری نداره.

2. یک ماژول بنویس تا این کار رو انجام بده، یا یک فایل راهنما تهیه کن و در اختیار کاربر قرار بده و در قراردادت ذکر کن اگر به اون عمل نکنند هیچ مسئولیتی در قبال از دست رفتن اطلاعات نخواهی داشت.

3. در وب اگر تصاویر زیاد شود توی پوشه بودن هم هزینه کمتری داره و هم سرعت بیشتری. به تفاوت هزینه پهنای باند و حجم دیتابیس در مقابل پهنای باند و حجم سرور دقت کن.

4. مسلما، ولی روش توی پوشه بودن روی وب خیلی کارآمد تر از روی اترنت یا ویندوز است.

-اگر مجبور باشی چند سایز از تصویرت داشته باشی، مسلما توی پوشه بهتره.

-اگر بخواهی می تونی با ابزاری مثل Cache این کارو انجام بدی ولی به نظرم اساسا کار خوبی نیست. چون اگر حجم عکسها زیاد باشد کلی از منابع سرور را هدر می دهد.

RoostaYeBekr
چهارشنبه 22 آبان 1387, 00:27 صبح
با سلام
باز هم از توضیحاتی که همگی دادید ، ممنون.

arsp_2004 (http://barnamenevis.org/forum/member.php?u=33355) گفته بودید:


. اگر کل تصاویر در یک پوشه باشند بک آپ گیری در دو مرحله خلاصه میشه: دیتابیس وفایل ها، اتوماتیک کردن این دو به صورت پشت سر هم کاری نداره.

من قبلا یک پروژه ای کار کرده بودم که تعداد تصاویر در پوشه اش ، آنقدر زیاد شده بود که به چند مگابایت می رسید . همانطور که قبلا هم گفتم ، این من نبودم که باید بک آپ می گرفتم . کس دیگری بود . حتی با rar کردن هم ، باز طول می کشید.
arsp_2004 (http://barnamenevis.org/forum/member.php?u=33355) گفته بودید:


یک ماژول بنویس تا این کار رو انجام بده، یا یک فایل راهنما تهیه کن و در اختیارکاربر قرار بده و در قراردادت ذکر کن اگر به اون عمل نکنند هیچ مسئولیتی در قبال ازدست رفتن اطلاعات نخواهی داشت.

من منظورتون رو از این حرف نمی فهمم . مگر کاربر قرار است از اطلاعات بک آپ بگیرد؟ اگر تصورتان از سوال من ، مثلا یک سیستم ایمیل زدن است که مسئولیت نگهداری فایلهایی که کاربر برای دیگران فرستاده ، را باید خودش داشته باشد ، خوب این که یک مسئله ی جداست . اینکه کاربر باید مسئولیت فایلهایش را داشته باشد ، یک چیز است ، و اینکه خود سرویس دهنده ی ایمیل هم باید از ایمیل کاربران و اطلاعاتشان و فایلهایشان ، بک آپ بگیرد ، یک چیز دیگر است . و منظور من بک آپ گیری است که مربوط به وظایف مسئولین سایت است.
arsp_2004 (http://barnamenevis.org/forum/member.php?u=33355) گفته بودید:


در وب اگر تصاویر زیاد شود توی پوشه بودن هم هزینه کمتری داره و هم سرعت بیشتری. بهتفاوت هزینه پهنای باند و حجم دیتابیس در مقابل پهنای باند و حجم سرور دقت کن.

خوب این حرفتان ، کاملا درست است.



tarhebartar (http://barnamenevis.org/forum/member.php?u=56432) گفته بودید :


همه این مطالب درسته ولی من کلا باز هم میگم از ریپیتر استفاده کن

شما GridView ای را در نظر بگیرید که شامل چند فیلد است:
1- نام کشور
2- نام شهر
3- نام شرکت
4- نوع شرکت ( اینکه چه وسیله ای تولید می کند)
5- نام وسیله ای که شرکت تولید کرده
6- عکس وسیله

به نظر شما عاقلانه تر نیست که از GridView استفاده کنیم؟ چون GridView هم امکان Paging دارد و هم امکان Sort کردن دارد.
فقط خواهش می کنم نگوئید که می توانی برنامه ای با Repeater یا DataList بنویسی که هم دو کار بالا را بکند و هم فیلتر بکند و هم سرچ کند. چون GridView را برای همین ساخته اند که این برنامه نویسی های طولانی را ما نکنیم.
tarhebartar (http://barnamenevis.org/forum/member.php?u=56432) گفته بودید :


در ضمن زیاد پیش نمییاد از دیتابیس برای ذخیره عکس استفاده بشه و باید برای کیفیتکار از پوشه استفاده کرد

متاسفانه خیلی زیاد برای بنده پیش آمده که باید همین کار را می کردم.

Chabok (http://barnamenevis.org/forum/member.php?u=6919) ، شما چقدر قشنگ منظور من را فهمیدی . راهنمایی هم که کردی ، راهنمایی خوبی بود که گفتید :


چاره این کار اینه که این هندلر شما اون دیتاسورسی رو که یک بار از دیتا پرشده رودر اختیار داشته باشه و بر اساس هر درخواست به اون دیتاسورس مراجعه کنه و از اونجاعکس رو بخونه .

البته ، این همون چیزی است که من از اول گفتم :


مثلا باید کاری می کردیم کهدر یک ارتباطتمام عکس ها را دریک DataTable بریزد و برنامه برای نمایش عکس ها از همین DataTable استفاده کند و دیگر هیچ ارتباطی با دیتابیس زده نشود چون قبلا تمام عکسها را گرفته.

و بعد هم گفتم که متاسفانه اگر این کار را با GridView بکنیم ، عکس ها نمایش داده نمی شود.
به احتمال زیاد راه حل هم همین است . یعنی باید یک جوری قضیه را به همین روش حل کنیم که من نمی دانم این تصاویری که از دیتابیس گرفته می شود و بعد در DataTable یا DataView ریخته می شود ، چه کارش کنم که .........

Chabok (http://barnamenevis.org/forum/member.php?u=6919) ، خیلی خوب هم متوجه شدی که صورت مسئله برایم مهم است. منظورم این است که ضمن تشکر از بقیه افرادی که سعی در راهنمایی من داشتند ، خواهش می کنم که از صورت مسئله دور نشوند . من نمی خواهم که :
1 – آدرس عکس ها را به جای خود عکس ها در دیتابیس ذخیره کنند.
2 – به هیچ عنوان نمی خواهم عکس هایی که قرار است مدام زیادتر شوند را در پوشه نگه داری کنم.
3 – صورت مسئله.

Chabok
چهارشنبه 22 آبان 1387, 17:48 عصر
با سلام . شما لطف دارید .

و بعد هم گفتم که متاسفانه اگر این کار را با GridView بکنیم ، عکس ها نمایش داده نمی شود.خوب من اول راه حل رو گفتم . مطمئنا با این پیاده سازی فعلی نمایش هم داده نمیشود .

اگر با این راه حل مشکلی نیست که بریم جلو :
شما باید هنگام پر کردن دیتاتیبل فیلد عکس رو هم Select کنید .
سپس این دیتاتیبل رو یه جایی در سطح Application ذخیره کنید (Cahce یا Application)
ولی به گرید ویو خود دست نزنید .
<%# "ImageFromDB.ashx?_id=" + Eval("_id") %>بزارید این سر جاش باشه .
شما فقط باید اون هندلر رو دستکاری کنید .
در هندلر باید اون ارتباط با دیتابیس رو کلاً قطع کنید .دیگه قراره کاری با دیتابیس نداشته باشیم . و باید بر اساس همین id پاس داده شده توی اون دیتاتیبل سرچ کنید و رکورد مورد نظرش رو پیدا کنید و بعدش هم سراغ اون فیلد عکس برید .
سپس همون کدهایی که برای بافرینگ و نوشتن روی response نوشتین رو روی این فیلد پیاده کنید و عکس رو برای کلاینت ارسال کنید .

موفق باشید . خدانگهدار

RoostaYeBekr
پنج شنبه 23 آبان 1387, 17:38 عصر
با سلام
من یک راه حلی با استفاده از صفحه های Default دارم ( منظورم این است که با HttpHandler نیست . البته خودم دوست داشتم با این HttpHandler باشد . ولی چون بلد نبودم در HttpHandler از session استفاده کنم ، این کار را کردم )

البته معایب برنامه ای که نوشتم را نمی دانم.

فایلش را برای هر کس دیگری که این سوال را مثل من دارد ، فرستادم.

RoostaYeBekr
پنج شنبه 23 آبان 1387, 19:31 عصر
با سلام
من یک راه حلی با استفاده از صفحه های Default دارم ( منظورم این است که با HttpHandler نیست . البته خودم دوست داشتم با این HttpHandler باشد . ولی چون بلد نبودم در HttpHandler از session استفاده کنم ، این کار را کردم )

البته معایب برنامه ای که نوشتم را نمی دانم.

فایلش را برای هر کس دیگری که این سوال را مثل من دارد ، فرستادم.

chabok ، کدی که برای استفاده از Session ها ، مربوط به پست زیر فرستاده بودید:
http://barnamenevis.org/forum/showpost.php?p=610942&postcount=6
را دیدم . ولی متاسفانه در HttpHandler جواب نمی دهد. من این پیغام را در پستی که می دانید ، فرستادم . ولی ظاهرا به دلیل اینکه آنجا یکی از اشکالات فنی سایت را گفته بودم ، لطف کردند ، کل پست را بدون هیچ اثری پاک کردند!!! حتما هم الان می خواهند به من پیغام بدهند که سوالت تکراری بود . در حالیکه من سوالم را قبل از پرسیدن در سایت سرچ کرده بودم . اون تاپیکی که قبلا بود ، در رابطه با کلاس ها بود و نه HttpHandler ها. فکر کنم دیگه این تاپیک قفل شود. شاید هم مثل همون تاپیکی که می دانی ، نیست شود.

Chabok
جمعه 24 آبان 1387, 11:56 صبح
با سلام

راستش من خودم اون تاپیک رو به عنوان تکراری گزارش کردم .:لبخند:
آقای راد هم به من اعتماد کردند و تاپیک رو پاک کردند.:چشمک:
چون فکر کردم تکراری است . ولی ظاهرا حق با شماست . و در HttpHandler ها دسترسی به session ها کمی سخت است :


The SessionState is handled by an HttpHandler, and it's possible that your
HttpHandler is called before the SessionState HttpHandler.

By implents the IRequiresSessionState (marker interface), you prevent your
HttpHandler to be called before the SessionState HttpHanlder, and so you can
use the session.

And if you only require read only session state, you implement IReadOnlySessionState
instead of IRequireSessionState.
ببینید این کد کمکی میکنه ؟
http://www.netnewsgroups.net/group/microsoft.public.dotnet.framework.aspnet/topic27233.aspx

و یا این لینک ها:
http://aspadvice.com/blogs/ssmith/archive/2007/07/29/Accessing-Session-from-an-HttpHandler.aspx
http://weblogs.asp.net/ashicmahtab/archive/2008/09/18/how-to-use-session-values-in-an-httphandler.aspx

در واقع باید چنین صورتی رو پیاده کنید :


class MyHttpHandler : IHttpHandler, IReadOnlySessionState // or IRequireSessionState if you want write access
{
public void ProcessRequest(HttpContext context)
{
string s = context.Session["SomeSessionVariable"];
}

public bools IsReusable { get { return true; } }
}

اگر موفق نشدید فکر کنم باید به فکر Cache یا Application باشید .
موفق باشید . خدانگهدار