لماذا من الممكن تعداد استعلام DBLINQ بعد استدعاء Dispose () على datacontext؟
سؤال
تحديث - يبدو أن الإجابة هي أن DBLINQ لا تنفذ Dispose()
بصورة صحيحة. دو!
فيما يلي كل نوع من أنواع المضللة - النتيجة النهائية: DBLINQ لا تعادل (حتى الآن) LINQTOSQL ، كما افترضت عندما طرحت هذا السؤال في الأصل. استخدامه بحذر!
أنا أستخدم نمط المستودع مع DBLINQ. تنفيذ كائنات المستودع الخاص بي IDisposable
, ، و ال Dispose()
الطريقة تفعل الشيء فقط- Dispose()
على ال DataContext
. كلما استخدمت مستودعًا ، ألفه في using
كتلة ، مثل هذا:
public IEnumerable<Person> SelectPersons()
{
using (var repository = _repositorySource.GetPersonRepository())
{
return repository.GetAll(); // returns DataContext.Person as an IQueryable<Person>
}
}
هذه الطريقة تُرجع IEnumerable<Person>
, ، لذلك إذا كان فهمي صحيحًا ، فلن يحدث أي استفسار عن قاعدة البيانات فعليًا حتى Enumerable<Person>
يتم اجتيازه (على سبيل المثال ، عن طريق تحويله إلى قائمة أو صفيف أو باستخدامها في أ foreach
حلقة) ، كما في هذا المثال:
var persons = gateway.SelectPersons();
// Dispose() is fired here
var personViewModels = (
from b in persons
select new PersonViewModel
{
Id = b.Id,
Name = b.Name,
Age = b.Age,
OrdersCount = b.Order.Count()
}).ToList(); // executes queries
في هذا المثال، Dispose()
يتم استدعاؤه مباشرة بعد الإعداد persons
, وهو أمر IEnumerable<Person>
, ، وهذه هي المرة الوحيدة التي يتم فيها تسمى.
لذلك ، ثلاثة أسئلة:
- كيف يعمل هذا؟ كيف يمكن التخلص
DataContext
لا يزال الاستعلام عن قاعدة البيانات للحصول على النتائج بعدDataContext
تم التخلص منه؟ - ماذا فعلت
Dispose()
في الواقع؟ - سمعت أنه ليس ضروريًا (على سبيل المثال ، انظر هذا السؤال) للتخلص من أ
DataContext
, ، لكن انطباعي كان أنها ليست فكرة سيئة. هل هناك أي سبب ليس للتخلص من dblinqDataContext
?
المحلول
1 كيف يعمل هذا؟ كيف يمكن ل datacontext التخلص أن يستمر في الاستعلام عن قاعدة البيانات للحصول على النتائج بعد التخلص من datacontext؟
هو - هي لا الشغل. هناك شيء لا تعرضه لنا. أظن أن فئة المستودع الخاصة بك لا تتخلص من DataContext
بشكل صحيح/في الوقت المناسب ، أو أنك تكتب بشكل ملحوظ ToList()
في نهاية كل استعلام ، والذي ينفي تمامًا تحول الاستعلام والتنفيذ المؤجل الذي تحصل عليه عادة.
جرب الرمز التالي في تطبيق اختبار ، أنا ضمان أنت سوف ترمي ObjectDisposedException
:
// Bad code; do not use, will throw exception.
IEnumerable<Person> people;
using (var context = new TestDataContext())
{
people = context.Person;
}
foreach (Person p in people)
{
Console.WriteLine(p.ID);
}
هذه هي أبسط حالة ممكنة استنساخ ، وسوف ترمي دائمًا. من ناحية أخرى ، إذا كتبت people = context.Person.ToList()
بدلاً من ذلك ، تم بالفعل تعداد نتائج الاستعلام داخل ال using
الحظر ، الذي سأراهن عليه هو ما يحدث في قضيتك.
2 ماذا تفعل () في الواقع؟
من بين أشياء أخرى ، يضع علامة تشير إلى أن DataContext
يتم التخلص منه ، والذي يتم فحصه في كل استعلام لاحق ويسبب DataContext
لرمي ObjectDisposedException
مع الرسالة Object name: 'DataContext accessed after Dispose.'.
كما أنه يغلق الاتصال ، إذا كان DataContext
فتحها وتركها مفتوحة.
3 سمعت أنه ليس من الضروري (على سبيل المثال ، انظر هذا السؤال) التخلص من datacontext ، لكن انطباعي كان أنها ليست فكرة سيئة. هل هناك أي سبب لعدم التخلص من datacontext LINQTOSQL؟
هو - هي هو ضروري ل Dispose
ال DataContext
, ، كما هو ضروري Dispose
كل شيء آخر IDisposable
. يمكن أن تتسرب من الاتصالات إذا فشلت في التخلص من DataContext
. يمكنك أيضًا تسرب الذاكرة إذا تم استرداد أي من الكيانات من DataContext
يتم الاحتفاظ بها على قيد الحياة ، لأن السياق يحافظ على ذاكرة التخزين المؤقت للهوية الداخلية لنمط وحدة العمل الذي تنفذه. ولكن حتى لو لم يكن أي من هذا هو الحال ، إنه ليس قلقك ماذا Dispose
الطريقة تفعل داخليا. افترض أنه يفعل شيئًا مهمًا.
IDisposable
هو عقد هذا يقول ، "قد لا يكون التنظيف تلقائيًا ؛ فأنت بحاجة إلى التخلص مني عند الانتهاء." ليس لديك أي ضمانات لما إذا كان للكائن مع نهائيات نهائية خاصة به ينظف بعدك إذا نسيت ذلك Dispose
. تخضع التطبيقات للتغيير ، وهذا هو السبب في أنه ليس من الجيد الاعتماد على السلوك المرصود بدلاً من المواصفات الصريحة.
أسوأ شيء يمكن أن يحدث إذا تخلصت من IDisposable
مع فارغة Dispose
الطريقة هي أنك تضيع بعض دورات وحدة المعالجة المركزية. أسوأ شيء يمكن أن يحدث إذا كنت يفشل للتخلص من IDisposable
مع التنفيذ غير التافهة هذا هو أنك تسرب الموارد. الاختيار هنا واضح ؛ إذا رأيت IDisposable
, ، لا تنسى التخلص منه.
نصائح أخرى
"الأشخاص" عبارة عن مجموعة غير قابلة للتطبيق ، لا يلزم سوى datacontext (مستودع) إجراء مكالمة .getNew.
الكلمات الرئيسية من/select/etc هي السكر النحوي لطرق التمديد المضافة في مساحة الاسم. تضيف طرق التمديد هذه الوظيفة التي تستخدمها في استعلامك ، وليس DataContext. في الواقع ، يمكنك القيام بكل هذا دون استخدام LINQ2SQL على الإطلاق ، عن طريق إنشاء برمجي لإظهار.
إذا حاولت إجراء أي مكالمات أخرى مستودع (DataContext) باستخدام هذه الكائنات ، فهذا هو عندما تتلقى خطأ.
ستحتوي مجموعة iEnumerable على جميع السجلات من مستودعك ، ولهذا السبب لا تتطلب DataContext لإجراء الاستعلام.
طرق التمديد: http://msdn.microsoft.com/en-us/library/bb383977.aspx
طرق تمديد LINQ:http://msdn.microsoft.com/en-us/library/system.linq.enumerable_members.aspx
في أعماق واجهة برمجة التطبيقات ، من المحتمل أن ترى طريقة باستخدام واجهة برمجة التطبيقات مثل هذه:
http://msdn.microsoft.com/en-us/library/y6wy5a0f(v=vs.100).aspx
عند تنفيذ الأمر ، يتم إغلاق كائن الاتصال المرتبط به عند إغلاق كائن DataReader المرتبط به.