ما هو الفرق بين تعبيرات الاستعلام LinQ وأساليب التمديد

StackOverflow https://stackoverflow.com/questions/796246

  •  18-09-2019
  •  | 
  •  

سؤال

فيما يلي استفسارين يعيدان نفس البيانات. البعض ثم النمط لست متأكدا وهو أفضل.

ما هي العوامل التي تؤثر على هذه الاستفسارات؟ ما هي فوائد استخدام أسلوب واحد على الآخر؟

عينة 1.

var x = from s in db.Surveys
    join sq in db.Survey_Questions on s.ID equals sq.Survey_ID
    join q in db.Questions on sq.Question_ID equals q.ID
    join qg in db.Question_Groups on q.ID equals qg.Question_ID
    where s.Type_ID.Equals(typeID) & s.Type.Equals(type)
    select new { question = sq.Question, status = sq.Status, grp = qg };

عينة 2

var x = db.Surveys.Where(s => s.Type_ID.Equals(typeID) & s.Type.Equals(type))
              .Join(db.Survey_Questions,
                        s => s.ID,
                        sq => sq.Survey_ID,
                        (s, sq) => new
                        {
                            question = sq.Question,
                            status = sq.Status
                        })
              .Join(db.Question_Groups,
                        q => q.question.ID,
                        qg => qg.Question_ID,
                        (q, qg) => new
                        {
                            question = q.question,
                            status = q.status,
                            group = qg
                        }).ToList();
هل كانت مفيدة؟

المحلول

تحديث: لقد قمت بإصلاح عنوانك، لذلك تجاهل التشدق.

عنوان سؤالك لا علاقة له بعينات التعليمات البرمجية. يتعين سؤالك أن بناء جملة واحد هو iEnaryerable والآخر IQueryable، ولكن هذا غير صحيح. في العينات الخاصة بك، إذا db.Surveys هو iqueryable، ثم على حد سواء العينات الخاصة بك تستخدم iqueryable. سأحاول الإجابة على حد سواء أسئلة.

عينات الشفرة الخاصة بك هي مجرد طرق مختلفة لكتابة نفس استفسارات LINQ (على افتراض أنها مكتوبة بشكل جيد). الرمز في العينة 1 هو مجرد اختصار للرمز في العينة 2. يتعامل المحول البرمجي على الكود في كلتا العينات بنفس الطريقة. فكر في الطريقة التي سيعاملها c # compiler int? كمثل Nullable<System.Int32>. وبعد توفر كل من لغات C # و VB.Net هذا بناء جملة استفسار الاختزال. قد لا تحتوي لغات أخرى على هذا بناء الجملة وسيتعين عليك استخدام بناء جملة العينة 2. في الواقع، قد لا تدعم لغات أخرى حتى طرق الإرشاد أو تعبيرات Lambda، وستحتاج إلى استخدام بناء جملة UGLIER بعد.


تحديث:

لأخذ مثال Sander أكثر، عند كتابة هذا بناء جملة فهم الاستعلام):

var surveyNames = from s in db.Surveys select s.Name

أنت فكر في يتحول المحول البرمجي إلى أن الاختصار في هذه (طرق الإرشاد والتعبير Lambda):

IQueryable<string> surveryNames = db.Surveys.Select(s => s.Name);

ولكن في الواقع طرق الإرشاد وتعبيرات لامدا هي اختصار أنفسهم. تنبعث البوكماء أن شيئا مثل هذا (ليس بالضبط، ولكن فقط لإعطاء فكرة):

Expression<Func<Survey, string>> selector = delegate(Survey s) { return s.Name; };
IQueryable<string> surveryNames = Queryable.Select(db.Surveys, selector);

لاحظ أن Select() هي مجرد طريقة ثابتة في Queryable صف دراسي. إذا لم تدعم لغة .NET الخاصة بك بناء جملة الاستعلام أو LambDAS أو طرق الإرشاد، فهذه هي كيندا كيف يتعين عليك كتابة الرمز بنفسك.


ما هي فوائد استخدام أسلوب واحد على الآخر؟

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

var items = source.Where(s => s > 5);

أيضا، يمكن أن يكون بناء جملة طريقة التمديد أكثر مرونة، مثل الشرطية حيث البنود:

var items = source.Where(s => s > 5);

if(smallerThanThen)
    items = items.Where(s => s < 10);
if(even)
    items = items.Where(s => (s % 2) == 0);

return items.OrderBy(s => s);

بالإضافة إلى ذلك، تتوفر العديد من الطرق فقط من خلال بناء جملة طريقة الملحق (العد ()، الإجمالي ()، خذ ()، تخطي ()، Tolist ()، TOLIT ()، إلخ)، لذلك إذا كنت سأستستخدم واحدة من هذه، عادة ما أكتب الاستعلام بأكمله في بناء الجملة هذا لتجنب خلط كل من التجميعات.

var floridaCount = source.Count(s => s.State == "FL");

var items = source
            .Where(s => s > 5)
            .Skip(5)
            .Take(3)
            .ToList();

من ناحية أخرى، عندما يصبح الاستعلاما أكبر وأكثر تعقيدا، يمكن أن يكون بناء جملة فهم الاستعلام أكثر وضوحا، خاصة بمجرد البدء في تعقيد مع عدد قليل let, group, join, ، إلخ.

في النهاية، سأستمر عادة أيهما يعمل بشكل أفضل لكل استفسار محدد.


تحديث: قمت بإصلاح عنوانك، لذا تجاهل الباقي ...

الآن، حول عنوانك: فيما يتعلق LinQ، IEnumerable و IQueryable مشابهة جدا. كلاهما لديهما نفس طرق التمديد نفسها (حدد، حيث، عد، إلخ)، مع الفرق الرئيسي (فقط؟) يجري Func<TIn,TOut> كما المظليين و IQueryable يأخذ Expression<Func<TIn,TOut>> كما المعلمات. أنت تعبر عن نفس الطريقة (عادة تعبيرات لامبا)، ولكن داخليا فهي مختلفة تماما.

ienumerable هو المدخل إلى LinQ إلى الكائنات. يمكن استدعاء طرق LinQ إلى كائنات تمديد على أي IEnumerable (صفائف، قوائم، أي شيء يمكنك التكرار به foreach) و ال Func<TIn,TOut> يتم تحويله إلى IL في وقت الترجمة ويتم تشغيله مثل رمز الطريقة العادية في وقت التشغيل. لاحظ أن بعض موفري Linq الآخرين يستخدمون iEnumerable وكذلك يستخدمون LinQ إلى الكائنات خلف الكائنات (LinQ إلى XML، LINQ إلى DataSet).

يتم استخدام IQueryable من قبل LinQ إلى SQL، LINQ إلى الكيانات، ومقدمي LinQ الآخرين الذين يحتاجون إلى فحص استفسارك وترجمته بدلا من تنفيذ التعليمات البرمجية الخاصة بك مباشرة. استعلامات iqueryable و Expression<Func<TIn,TOut>>لا يتم تجميعها في IL في وقت Compile. بدلا من ذلك شجرة التعبير يتم إنشاؤها ويمكن فحصها في وقت التشغيل. يتيح ذلك ترجمة العبارات المراد تترجمها إلى لغات استعلام أخرى (على سبيل المثال T-SQL). يمكن تجميع شجرة التعبير في Funcu003CTIn,TOut> في وقت التشغيل وتنفيذه إذا رغبت في ذلك.

مثال يوضح الفرق يمكن العثور عليه هذا السؤال حيث يريد OP القيام بجزء من LinQ إلى SQL Query في SQL Server، قم بإحضار الكائنات إلى التعليمات البرمجية المدارة، وقم ببقية الاستعلام في LinQ إلى الكائنات. لتحقيق هذا كل ما يتعين عليه فعله هو يلقي iqueryable في ienumerable حيث يريد أن يحدث التبديل.

نصائح أخرى

Linq هو كلمة الطنانة لتكنولوجيا.

IQueryable هو واجهة .NET التي يتم استخدامها بواسطة LinQ.

بخلاف النمط، لا يوجد فرق بين الاثنين. استخدم أي نمط تفضله.

أفضل النمط الأول للبيان الطويل (مثل هذا واحد يظهر هنا) والثاني لبيانات قصيرة للغاية.

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

    public class MyClass
    {

        public MyClass Where<T>(Func<MyClass, T> predicate)
        {
            return new MyClass { StringProp = "Hello World" };
        }

        public MyClass Select<T>(Func<MyClass, T> predicate)
        {
            return new MyClass ();
        }



        public string StringProp { get; set; }
    }

من الواضح أن هذا مثال غبي، ولكن لاحظ أن هناك طريقة إرجاع myclass جديدة فقط مع مجموعة StringProp إلى World Hello World. لتوضيح:

MyClass a = new MyClass();
            var q = from p in a
                    where p.StringProp == "foo" // doesnt matter what we put here, as we're not really checking the predicate
                    select p;
            Console.WriteLine(q.StringProp);

سيؤدي ذلك إلى كتابة "Hello World". مرة أخرى، من الواضح أن هذا المثال من الواضح أنه لا طائل من الواضح، لكنه يثبت أن بناء الجملة "حيث" يبحث بناء الجملة فقط عن الطريقة التي تؤدي إليها الكود الخاص بك.

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

عندما تكتب هذا:

var surveyNames = from s in db.Surveys select s.Name;

التحويل البرمجي يحول هذا إلى:

IQueryable<string> surveryNames = db.Surveys.Select(s => s.Name);

في الحقيقة، أعتقد أن تعبيرات الاستعلام تم إنشاؤها للتو لأسباب تسويقية - بناء لغة تشبه SQL للعمل كمرض للعين عندما تم تطوير LINQ، وليس شيئا يقدم الكثير من الاستخدام الفعلي. أجد أن معظم الناس يستخدمون أساليب التمديد مباشرة، لأنها تؤدي إلى نمط ترميز أكثر موحدة، بدلا من مزيج من C # و SQL.

1. / عنوان سؤالك لا يتطابق مع ما طلبته.
2. / عنوان سؤالك لا معنى له حقا. Linq تقف لاستعلام اللغة المتكاملة وهو مصطلح مظلة لمجموعة من التقنيات والممارسات، IQueryable هي واجهة تستخدم عادة لتسهيل LINQ. أنت تقارن التفاح والبرتقال
3. / حول سؤالك الفعلي، الفرق الرئيسي هو النمط، للحصول على استفسارات معقدة مثل هذا واحد، تفضيلاتي الشخصية هي الإصدار الثاني، لأنه يظهر بوضوح تطور مجموعات النتائج.

لك sample1. هو تمثيل المستوى الأعلى ل LINQ، إنه أكثر قابلية للقراءة، وبينما يتم تحويله إلى شجرة التعبير أي sample2..

var x = from s in db.Surveys
    join sq in db.Survey_Questions on s.ID equals sq.Survey_ID
    join q in db.Questions on sq.Question_ID equals q.ID
    join qg in db.Question_Groups on q.ID equals qg.Question_ID
    where s.Type_ID.Equals(typeID) & s.Type.Equals(type)
    select new { question = sq.Question, status = sq.Status, grp = qg };

يمكنك تجربة رمز أدناه للحصول على تعبير لاستعلام مكتوب

var exp=x.Expression;

يتم استخدام التعبيرات عند الاستعلام أقل تعقيدا

أعتقد أن سؤالك هو أفضل صيغة مثل هذا، "ما هو الفرق بين ienumerableu003CT> و iqueryable.u003CT> فيما يتعلق LinQ "

استفسارات LinQ إرجاع IQueryableu003CT> بشكل افتراضي. Iqueryable.u003CT> يتيح لك إلحاق المرشحات الأخرى أو "Clauses" على استفسارك قبل تنفيذها.

استعلام LinQ الخاص بك (مثال أولا) و LinQ باستخدام طريقة التسلسل (المثال الثاني) تنتج نفس النتيجة، مع بناء جملة مختلف.

من الممكن كتابة استعلام LinQ كسلسلة طريقة LinQ و Versa. حقا يعتمد على تفضيلاتك.

Lucas: مختلف هو ienumerableu003CT> هل في الذاكرة الاستعلام و iqueryableu003CT> هل خارج الذاكرة. معنى، بمجرد أن تكون في foreach Iterator، أنت تستخدم iEnumerable، وعندما تقوم ببناء استفسارك، عبر طرق الإرشاد أو استخدام LinQ from o in object Synatax، أنت تقوم ببناء IQueryableu003CT> وبعد iqueryable.u003CT> يتم تنفيذها بمجرد أن تلمس العداد.

نقطة أخرى جديرة بالذكر هي أن أساليب ملحق LINQ تلتزم باللغة C # في حين أن الاشياء فهم الاستعلام يتم دمجها مسبقا في التحويل البرمجي. أي يمكنك الانتقال إلى تعريف. حدد (x => في حين لا يمكنك from ... where ... select

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