كيفية استخدام Left Join
بشكل أنيق مع SQL المجمّع في LINQ
عند العمل مع قواعد البيانات، يجد المطورون أنفسهم غالبًا في حاجة إلى إجراء استعلامات معقدة تتطلب معالجة البيانات واسترجاعها بشكل فعال. إحدى المهام الشائعة هي استخدام LEFT JOIN
في استعلامات SQL بالاقتران مع الدوال المجمعة. كيف يمكننا تحويل مثل هذه الاستعلامات SQL إلى تعبير أنيق في LINQ بلغة C#؟ في هذا المنشور، سوف نستعرض مثالًا على SQL ثم نغوص في معادله LINQ، مع تحليل العملية لزيادة الوضوح.
فهم استعلام SQL
لنلقي نظرة على عبارة SQL التي نريد ترجمتها:
SELECT
u.id,
u.name,
isnull(MAX(h.dateCol), '1900-01-01') dateColWithDefault
FROM universe u
LEFT JOIN history h
ON u.id = h.id
AND h.dateCol < GETDATE() - 1
GROUP BY u.Id, u.name
تحليل استعلام SQL
- اختيار الأعمدة: يستخلص الاستعلام معرف المستخدم (
u.id
)، اسم المستخدم (u.name
)، وأقصى تاريخ من سجلات التاريخ التي تتعلق بكل مستخدم (MAX(h.dateCol)
)، والذي يتم تعيينه إلى ‘1900-01-01’ في حال عدم وجود سجلات تاريخ. - الانضمام إلى الجداول: يتم استخدام
LEFT JOIN
لدمج البيانات من جدولuniverse
(u
) وجدولhistory
(h
)، مع شرط يقوم بتصفية سجلاتhistory
حيث يكونdateCol
أقدم من يوم واحد. - التجميع: يتم تجميع النتائج حسب معرف المستخدم واسم المستخدم، مما يضمن ظهور كل مستخدم مرة واحدة فقط في النتيجة.
ترجمة SQL إلى LINQ
للحصول على نفس نتيجة استعلام SQL باستخدام LINQ
، يمكننا هيكلة استعلامنا على النحو التالي:
DateTime yesterday = DateTime.Now.Date.AddDays(-1);
var collection =
from u in db.Universe
select new
{
u.id,
u.name,
MaxDate = (DateTime?)
(
from h in db.History
where u.Id == h.Id
&& h.dateCol < yesterday
select h.dateCol
).Max()
};
تفسير استعلام LINQ
-
إعلان المتغيرات: نقوم بإنشاء متغير من نوع
DateTime
يسمىyesterday
، والذي يمثل التاريخ المحدد ليوم واحد قبل التاريخ الحالي. هذا يعكس منطق SQL الذي يقارنdateCol
مع التاريخ الحالي ناقص واحد. -
هيكلة الاستعلام:
- فقرة From: نبدأ باختيار المستخدمين من جدول
Universe
. - Select New: يقوم هذا بإنشاء كائن مجهول لكل مستخدم يتضمن معرفه، واسم، وأقصى تاريخ من جدول
History
.
- فقرة From: نبدأ باختيار المستخدمين من جدول
-
الاستعلام الفرعي للتاريخ الأقصى:
- نبدأ استعلامًا فرعيًا لاختيار
dateCol
من جدولHistory
حيث تتطابق المعرفات وdateCol
أقل من يوم أمس. - بعد ذلك، نحسب التاريخ الأقصى باستخدام الطريقة
.Max()
.
- نبدأ استعلامًا فرعيًا لاختيار
ملاحظات إضافية
- معالجة القيم الفارغة: نظرًا لأن التاريخ الأقصى قد يكون فارغًا (لا توجد سجلات تاريخ)، نقوم بتحويله إلى
DateTime?
للسماح بالقيم القابلة للإفراغ. - اختلافات في المخرجات: على الرغم من أن نهج LINQ لا ينتج بالضبط نفس SQL، إلا أنه ينتج منطقياً نفس النتائج، مما يوضح أن ترجمة SQL المعقدة إلى LINQ يمكن أن تكون دقيقة.
الخاتمة
بينما قد تبدو ترجمة استعلامات SQL مع LEFT JOIN
والتجميع إلى LINQ لأول وهلة شاقة، فإن فهم مكونات عبارة SQL يسمح لنا باتباع نهج أكثر منهجية عند تحويلها إلى LINQ. من خلال تطبيق نفس المنطق بوضوح في عبارات LINQ، يمكنك الحفاظ على ليس فقط الوظائف ولكن أيضًا الوضوح في الكود الخاص بك.
مع الممارسة، ستصبح معالجة الاستعلامات المعقدة في LINQ طبيعة ثانية لك، مما يوفر لك وسيلة فعالة لضمان أن يكون استرجاع البيانات لديك فعالًا قدر الإمكان.