لماذا يتم خداع LINQ إلى SQL بواسطة طريقة التمديد؟ماذا الان؟

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

سؤال

النظر في بلدي Event الطبقة، والتي أقوم بتخزينها DateTime's في قاعدة البيانات كتواريخ UTC.أريد ببساطة إرجاع نطاق تمت تصفيته استنادًا إلى التاريخ الحالي في منطقة زمنية معينة - أليس كذلك؟

هذا يعمل بشكل جيد:

IQueryable<Event> test1 = this.GetSortedEvents().Where(e => e.FinishDateTime.Date >= DateTime.UtcNow.Date);

وهذا يعمل بشكل جيد أيضًا:

IQueryable<Event> test2 = this.GetSortedEvents().Where(e => e.FinishDateTime.AddHours(3).Date >= DateTime.UtcNow.AddHours(3).Date);

..ويلبي بالإضافة إلى ذلك متطلبات المنطقة الزمنية الخاصة بي.

لذلك أفكر هنا أنه يمكنني نقل هذا التحويل المحدد إلى طريقة الامتداد هذه:

    public static DateTime RiyadhTimeFromUtc(this DateTime utcTime)
    {
        return utcTime.AddHours(3);
    }

هذا لا يعمل:

IQueryable<Event> test3 = this.GetSortedEvents().Where(e => e.FinishDateTime.RiyadhTimeFromUtc().Date >= DateTime.UtcNow.RiyadhTimeFromUtc().Date);

..وأحصل على NotSupportedException:لا يحتوي الأسلوب 'System.DateTime الرياضTimeFromUtc(System.DateTime)' على ترجمة معتمدة إلى SQL.

من الواضح أن هذا هراء لأن المترجم قام بتحويله بسعادة إلى SQL عندما لم يكن الكود المطابق موجودًا في طريقة الامتداد.

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

إذا كان بإمكان أي شخص أن يخبرني بالخطأ الذي أفعله هنا (أو طريقة حل بديلة مختلفة لهذه المشكلة) سأكون ممتنًا حقًا.

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

المحلول

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

عند دراسة شجرة سوف ترى وجوه DateTime ومن ثم تحقق ما إذا كان أسلوب دعا هو واحد من تلك المدعومة (Add، AddHours، الخ) وذلك عند استخدام طريقة مباشرة أنه يعمل بشكل جيد.

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

والنقطة أساليب خلق هو التغليف والمعلومات الاختباء، والتي تعمل عادة بشكل جيد في تطوير التطبيقات، ولكن للأسف هنا انها إخفاء المعلومات من ينق إلى SQL الذي عليك أن تكون قادرا على رؤية المعلومات.


وردا على سؤال المحرر - كيف يمكن حل هذا؟ إذا كنت تريد أن تبقي على حساب تاريخ في التعبير ينق، والشيء الوحيد الذي يمكنك القيام به للحفاظ على كفاءة الاستعلام ليس لاستخدام أسلوب الإرشاد، ومجرد استخدام AddHours(3) مباشرة على الكائن DateTime.

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

نصائح أخرى

يبدو أن LINQ-to-SQL قادر على اكتشاف ذلك RiyadhTimeFromUtc كانت في الحقيقة مجرد دعوة ل AddHours(3) سيتعين عليها إجراء بعض التحليلات المعقدة جدًا للتعليمات البرمجية الخاصة بك.قل أنك كتبت:

public static DateTime RiyadhTimeFromUtc(this DateTime utcTime)
{
    if (Random.GetInt() < 99) {
       return utcTime.AddHours(3);
    } else {
       return utcTime.AddDays(5);
    }
}

كيف يمكن ترجمة ذلك إلى SQL؟يرى هذه المناقشة لمزيد من المعلومات.

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