ورود

View Full Version : بستن منابع در linq



jaykob
شنبه 12 آذر 1390, 17:36 عصر
سلام دوستان

در Linq To Sql زمانی که ما یک پرس و جو رو انجام می دیم آیا احتیاج هست که ارتباط خودمون رو با کلاس قطع کنیم که از منابع سرور کمتر استفاده بشه ؟ لطفا یک مثال هم بزنید

با تشکر

mehdi.mousavi
دوشنبه 14 آذر 1390, 12:15 عصر
سلام دوستان در Linq To Sql زمانی که ما یک پرس و جو رو انجام می دیم آیا احتیاج هست که ارتباط خودمون رو با کلاس قطع کنیم که از منابع سرور کمتر استفاده بشه ؟ لطفا یک مثال هم بزنید با تشکر

سلام.
در استفاده از ADO همواره توصیه بر این بوده که به محض اینکه کارمون با بانک تموم میشه (فرضا رکورد در بانک درج میشه، حذف میشه یا Query مورد نظر ما انجام میشه)، Connection رو Close کنیم تا عمل Connection Pooling با کارایی بالا به کار خودش ادامه بده.

Connection Pooling چیه؟ وقتی می خواهیم به بانک متصل بشیم و داده ای رو از اون بگیریم یا در اون بنویسیم، برقراری این ارتباط در فازهای متنوعی صورت میگیره. ابتدا یک کانال ارتباطی مانند Socket یا Named Pipe باید ایجاد بشه، اطلاعات اولیه مورد نیاز برای برقراری ارتباط باید رد و بدل بشه (بین Client و Server)، سپس Connection String تعیین شده توسط ما باید Parse بشه، ارتباط باید توسط سرور Authenticate بشه، اگر نیاز به Enlist شدن در یک رویه Transactional هستش باید روند مورد نیاز طی بشه و ...

مشخصه که انجام این امور، هر بار از ابتدا، بسیار زمان بر و CPU Intensive هستش. بنابراین، Connection ها هنگام بسته شدن در استخری از Connection ها قرار میگیرن که بهش Connection Pool میگیم. وقتی Connection ای Close میشه، منابع مورد نیاز آزاد میشه، اما Socket یا Named Pipe مربوطه بعلاوه برخی دیگه از فازهای اولیه برقراری ارتباط با سرور در استخر نام برده نگهداری میشه (برای مدت زمان مشخصی). سپس، هر وقت Connection جدیدی باز میشه، سیستم ابتدا به Connection Pool مراجعه میکنه تا ببینه آیا میتونه یکی از Connection های موجود رو برای استفاده به Client ارائه کنه یا نه. اگر این عمل شدنی باشه، یکی از Connection های موجود هنگام Open شدن Connection به Client برمیگرده، در غیر اینصورت، روند برقراری ارتباط با سرور از ابتدا طی میشه تا Connection مورد نیاز ما ایجاد بشه.

بصورت پیش فرض، Connection Pooling در ADO.NET فعال هستش و LINQ to SQL نیز از ADO.NET در لایه زیری خودش بهره میبره. بنابراین، در پاسخ به سوال شما باید بگم بهترین روش برای استفاده از Data Context ایجاد شده در LINQ to SQL، ایجاد Data Context هنگام نیاز و Dispose کردن اون بلافاصله پس از اتمام کار هستش. اما، باید مراقب Deferred Loading نیز باشید. بخش Disposing and Deferred Loading در این مقاله (http://leedumond.com/blog/about-disposing-the-datacontext/) شما رو با جزئیات آشنا میکنه.

موفق باشید.

jaykob
دوشنبه 14 آذر 1390, 17:41 عصر
سلام

آقای موسوی ممنون از راهنمایی خیلی خوبتون . کد ساده ای که من از حرف های شما برداشت کردم باید به شکل زیر باشه :



DataClassesDataContext db = new DataClassesDataContext();
var q = from i in db.tbl_contacts select i.name;
foreach (string item in q)
Response.Write(item);
db.Dispose();



شما جوری این کوئری هارو در نظر بگیرید که در یک ساعت بالای هزار تا ثبت نام یا نمایش پروفایل قراره صورت بگیره و به همین دلیل دنبال بهینه کردن کوئری هام هستم و به بحث LINQ TO SQL هم مسلط نیستم به کمک شما احتیاج دارم .

در ضمن من در کنترل پنل پلسک هم dedicated pooling رو فعال کردم این گزینه تا چه حد تاثیر داره ؟

در رابطه با Deferred Loading که فرمودید لینک رو دیدم اما به دلیل ضعف در زبان انگلیسی و عدم پیش زمینه فنی کامل متوجه نشدم ممنون می شم همرا با یک مثال این موضوع رو توضیح بدید . این بحث بهینه کردن کوئری هام خیلی برام مهم هست .

با تشکر

mehdi.mousavi
شنبه 19 آذر 1390, 16:53 عصر
سلام.
کد شما رو مجددا می نویسم تا بتونم روی اون براتون توضیح بدم:


DataClassesDataContext db = new DataClassesDataContext();
var q = from i in db.tbl_contacts select i.name;
foreach (string item in q)
Response.Write(item);
db.Dispose();

فرض کنید به هر دلیلی، کد شما در خط for-each اجراش با throw شدن Exception ای متوقف بشه. بنابراین، اجرا به خط db.Dispose نمیرسه. بنابراین، بهتره کد فوق رو بدین شکل بنویسید:

using (DataClassesDataContext db = new DataClassesDataContext())
{
var q = from i in db.tbl_contacts select i.name;
foreach (string item in q)
Response.Write(item);
}

این کد، معادل کد اول هستش، با این تفاوت که هر وقت اجرا از Block مربوطه خارج بشه، db object خودش بطور خودکار Dispose میشه... کد فوق مشکلی نداره و فقط منجر به ایجاد و اجرای یک SQL Statement ساده میشه. بنابراین از نظر Performance مشکلی نخواهد داشت. اما وقتی میفرمایید در یک ساعت بالای هزار تا نمایش پروفایل قراره صورت بگیره، بنابراین اینجا Caching بسیار اهمیت پیدا میکنه. من از روی Response.Write ای که نوشته اید به این نتیجه رسیدم که کد رو برای استفاده در ASP.NET میخواهید که اگر این برداشت صحیح باشه، کاری که انجام داده اید چندان جالب نیست. شما در ASP.NET باید با ایجاد Web Control ها به هدفتون برسید. به این ترتیب، میتونید خروجی کنترل ها رو Cache کنید تا دیگه ASP.NET Runtime مجبور به طی کردن پروسه Page Life Cycle نباشه و فقط خروجی Cache شده رو به Client ارسال کنه. شما Caching رو میتونید بسته به نیاز در چندین نقطه در ASP.NET انجام بدید و این مساله ارتباطی به LINQ to SQL نداره... به گمانم قبلا در این مورد در یکی دو تاپیک مطالبی نوشته باشم، لطفا جستجو کنید.

اما در مورد Deferred Loading... وقتی شما کد رو به شکل فوق می نویسید، انجام Query در بانک در حلقه for-each و هنگام Enumerate شدن اون query رخ میده. حالا فرض کنید جای اینکه foeach رو در using block نوشته باشیم، اونو خارج از اون نوشته باشیم (با فرض اینکه q خارج از block تعریف شده باشه). بدین ترتیب، وقتی for-each رو خارج از using block می نویسیم، Query پس از Dispose شدن db context انجام میشه و نتیجه خطای System.ObjectDisposedException: Cannot access a disposed object. خواهد بود... (اما این ربطی به Deferred Loading نداره، اینو گفتم تا داستان رو متوجه بشید).

Deferred Loading چیه؟ وقتی داده ای رو از جدولی می گیریم، فقط اطلاعات همون جدول به دست ما میرسه. حالا فرض کنید، ما داده های جدولی که با این جدول در ارتباط هستش رو تقاضا می کنیم. اگر DB Context ما Dispose نشده باشه، LINQ to SQL میره و بر اساس خواسته ما Query ی جدیدی روی بانک انجام میده (بصورت Implicit) تا اطلاعات جدول مرتبط رو Load کنه. اما اگر DB Context مربوطه Dispose شده باشه، طبیعتا نمیتونه Query ی جدید رو انجام بده و ما با خطای فوق الذکر مواجه میشیم... حالا دو راه وجود داره برای اینکه جلوی چنین اتفاقی رو بگیریم. اول اینکه Property ی DeferredLoadingEnabled رو روی DB Context امون false بذاریم تا بطور خودکار داده های جداول مربوطه بارگذاری نشن. دومین روش، این هستش که نذاریم DB Context امون Dispose بشه...

موفق باشید.