سؤال

كيف يمكنك الحمل كسول قوائم متداخلة دون تنفيذ الاستعلام بالفعل؟ باستخدام مثال أساسي للغاية، قل لدي:

class CityBlock {
     IList<Building> BuildingsOnBlock;
     Person BlockOwner;
}

class Building {
     IList<Floor> FloorsInBuilding;
}

class Floor {
     IList<Cubicle> EmployeeCubicles;
}

Class Cubicle {
     System.Guid CubicleID;
     Person CubicleOccupant;
}

ثم في طبقة مستودعي، لدي الطريقة التالية:

GetCityBlocks()

ثم في طبقة الخدمة، سأحصل على GetCityBlockSbyowner، حيث استخدم طريقة تمديد للحصول على كتل المدينة مملوكة لشخص معين، كما يقول إننا نريد فقط كتل Guido:

GetCityBlocks().ForOwner("Guido")

إذا فعلنا ذلك. في المستودع () في المستودع، ستقوم بتنفيذ الاستفسارات - التي ستكون سخيفة لأننا لا نعرف من الذي يحصلن على هذا المستوى. لذلك السؤال هو، كيف نفعل هذا بكفاءة؟

دعونا نفترض أن هناك 50000 من مالكي كتلة، وبعض كتل مدينة 1000000، تحميل كلها ليست خيارا. باستخدام iqueryables لن تعمل بسبب التعشيش (بدون اختراق متطرف، على الأقل أنني أدرك). أيضا، إذا حاولت استخدام شيء مثل Lazylist Rob Corery، فيمكننا في الأساس أن يكون لدينا تسرب من دال لدينا في نماذج المجال الخاصة بنا، والتي قد تكون سيئة للغاية في المستقبل.

إذن كيف أذهب للقيام بذلك بشكل صحيح؟

  • هل هي مسألة تحديد السياق الصحيح؟ إذا كان الأمر كذلك، هل نفعل ذلك في طبقة مستودع، أو طبقة الخدمة؟
  • هل أنا نصف ميلد معا طبقة الخدمة وطبقة مستودعي للحصول على طرق خدمة محددة للغاية؟
  • أو هل أنا أفتقد شيئا كليا؟ (لا تزال جديدة نسبيا في شيء LINQ2SQL، والذي يتم التخلص التدريجي على أي حال ...)

تعديل:في نمط المستودع، يتم تعييننا حاليا في كائنات المجال الخاصة بنا، لذلك سيبدو شيئا مثل هذا:

public IQueryable<CityBlock> GetCityBlocks(){
    var results = from o in db.city_blocks
                  let buildings = GetBuildingsOnBlock(o.block_id)
                  select new CityBlock {
                      BuildingsOnBlock = buildings,
                      BlockOwner = o.block_owner
                  };
    return results;
}

لهذا العمل، يجب أن نحصل على المباني الحصول على .tolist ()، ما لم نجعل هذا الحقل الفعلي في كائن CityBlock، وهو لا يبدو صحيحا، لأنه يبدو كما لو كانت القوة كثيرا منحت لأي شخص يصل إلى حقل CityBlock.BuildingSonBlock. هل هذا الخرائط إلى كائنات المجال لدينا شيء يجب أن نفعله في طبقة الخدمة؟

هل كانت مفيدة؟

المحلول

أنت تفعل ذلك عن طريق إرجاع iqueryables بدلا من ilists.

Tolist () يؤدي الاستعلامات إلى التنفيذ فورا، لأنه يجب إجراء التحويل من Iqueriable إلى Ilist.

طالما أنك تقوم بإرجاع IQueryables Lazy Loading يجب إرجاء الإعدام حتى يتم حاجة البيانات بالفعل، أي متى يسمى Tolist ().

لا يمكنني العثور على إشارة في الوقت الحالي، لكني فهمي أنه إذا قمت بذلك بهذه الطريقة، فستكل LinQ إلى SQL الفرصة لتحسين SQL الذي يرسله إلى الخادم. وبعبارة أخرى، فسوف يقرأ في النهاية هذه السجلات:

GetCityBlocks().ForOwner("Guido")

بدلا من هذه السجلات:

GetCityBlocks()

نصائح أخرى

يمكنك تجربة نهج مختلف في تعيين كائنات المجال الخاصة بك لجعله يعمل. المشكلة هي أنه بغض النظر عما تفعله (ما لم تقم بتغيير قوائمك إلى iqueryables في كائنات المجال الخاصة بك)، فسوف ينتهي بك الأمر إلى Tolist () ING أثناء رسم الخرائط.

في الاتجاه الآخر للسماح ل LINQ2SQL بالتعيين إلى Pocos الخاص بك عن طريق إنشاء DataContext مخصص وعدم استخدام مصمم التعيين :)، بهذه الطريقة يمكنك الحفاظ على طراز المجال الخاص بك نظيفا واسمحوا LinQ2SQL بملء التبعيات في الوقت الصحيح. لاحظ أن الدخول إلى هذا الطريق له مشاكل خاصة به، ولكن يمكن القيام به.

إليك رابط لتبدأ في هذا الطريق

تحقيق Poco S في LinQ إلى SQL

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top