كيفية القيام بما يلي: تنفيذ عمليات ربط مخصصة (دليل البرمجة لـ #C)

يوضح هذا المثال كيفية تنفيذ عمليات الربط الغير ممكن تنفيذها بجملة join. في تعبير الاستعلام, جملة الـ join محددة ومحسنة لـ equijoins وهي عبارة عن الطريقة الأكثر شيوعاً في عمليات الربط. عند تنفيذ عملية equijoin، من المحتمل أنك ستحصل دائماً على الأداء الأفضل باستخدام جملة join.

ومع ذلك، هناك بعض الحالات التي لا يمكن استخدام جملة join فيها:

  • عندما تستند عملية الربط على تعبير عدم تساوي (ليست بـ equijoin).

  • عندما تستند عملية الربط على أكثر من تعبير مساواة أو عدم مساواة.

  • إذا كان عليك تقديم متغير نطاق مؤقت لتسلسل الجانب الأيمن (الداخلي) قبل عملية الربط.

لتنفيذ عمليات ربط ليست بـ equijoins، يمكنك استخدام عدة جمل from لإدخال كل مصدر بيانات بشكل مستقل. ثم قم بتطبيق تعبير تقييم في جملة where لمتغير النطاق لكل مصدر. يمكن أن يكون التعبير على شكل اتصال بأسلوب.

ملاحظة

لا تخلط بين هذا النوع من عملية الربط المخصص مع الاستخدام المتعدد لجمل from للوصول إلى المجموعات الداخلية. لمزيد من المعلومات، راجع جملة الربط (مرجع C#).

مثال

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

تنتج الطريقة الثانية سلسلة من كل المنتجات ذات معرف الفئة المسرود في قائمة الفئات على الجانب الأيسر. لاحظ استخدام جملة let والأسلوب Contains لإنشاء صفيف مؤقت. يمكن أيضاً إنشاء الصفيف قبل الاستعلام وإزالة جملة from الأولى.

     class CustomJoins
     {

         #region Data

         class Product
         {
             public string Name { get; set; }
             public int CategoryID { get; set; }
         }

         class Category
         {
             public string Name { get; set; }
             public int ID { get; set; }
         }

         // Specify the first data source.
         List<Category> categories = new List<Category>()
 { 
     new Category(){Name="Beverages", ID=001},
     new Category(){ Name="Condiments", ID=002},
     new Category(){ Name="Vegetables", ID=003},         
 };

         // Specify the second data source.
         List<Product> products = new List<Product>()
{
   new Product{Name="Tea",  CategoryID=001},
   new Product{Name="Mustard", CategoryID=002},
   new Product{Name="Pickles", CategoryID=002},
   new Product{Name="Carrots", CategoryID=003},
   new Product{Name="Bok Choy", CategoryID=003},
   new Product{Name="Peaches", CategoryID=005},
   new Product{Name="Melons", CategoryID=005},
   new Product{Name="Ice Cream", CategoryID=007},
   new Product{Name="Mackerel", CategoryID=012},
 };
         #endregion

         static void Main()
         {
             CustomJoins app = new CustomJoins();
             app.CrossJoin();
             app.NonEquijoin();

             Console.WriteLine("Press any key to exit.");
             Console.ReadKey();
         }

         void CrossJoin()
         {
             var crossJoinQuery =
                 from c in categories
                 from p in products
                 select new { c.ID, p.Name };

             Console.WriteLine("Cross Join Query:");
             foreach (var v in crossJoinQuery)
             {
                 Console.WriteLine("{0,-5}{1}", v.ID, v.Name);
             }
         }

         void NonEquijoin()
         {
             var nonEquijoinQuery =
                 from p in products
                 let catIds = from c in categories
                              select c.ID
                 where catIds.Contains(p.CategoryID) == true
                 select new { Product = p.Name, CategoryID = p.CategoryID };

             Console.WriteLine("Non-equijoin query:");
             foreach (var v in nonEquijoinQuery)
             {
                 Console.WriteLine("{0,-5}{1}", v.CategoryID, v.Product);
             }
         }
     }
     /* Output:
 Cross Join Query:
 1    Tea
 1    Mustard
 1    Pickles
 1    Carrots
 1    Bok Choy
 1    Peaches
 1    Melons
 1    Ice Cream
 1    Mackerel
 2    Tea
 2    Mustard
 2    Pickles
 2    Carrots
 2    Bok Choy
 2    Peaches
 2    Melons
 2    Ice Cream
 2    Mackerel
 3    Tea
 3    Mustard
 3    Pickles
 3    Carrots
 3    Bok Choy
 3    Peaches
 3    Melons
 3    Ice Cream
 3    Mackerel
 Non-equijoin query:
 1    Tea
 2    Mustard
 2    Pickles
 3    Carrots
 3    Bok Choy
 Press any key to exit.
      */

في المثال التالي، يجب على الاستعلام ربط تسلسلين استناداً إلى المفاتيح المطابقة التي في حالة أنه لا يمكن الحصول على التسلسل الداخلي (الجانب الأيمن) قبل جملة الربط نفسها. إذا تم تنفيذ هذا الربط بجملة join فإنه يجب استدعاء الأسلوب Split لكل عنصر. الاستخدام المتعدد لجمل from يمكّن الاستعلام من تجنب حمل الاستدعاءات المتكررة للأسلوب. ومع ذلك، بما أن الربط مُحسَّن، فإن في هذه الحالة الخاصة قد لا يزال الربط أسرع من الاستخدام المتعددة لجمل from. تتنوع النتائج حسب أساساً ثمن استدعاء الأسلوب.

class MergeTwoCSVFiles : StudentClass
{
    static void Main()
    {
        string[] names = System.IO.File.ReadAllLines(@"../../../names.csv");
        string[] scores = System.IO.File.ReadAllLines(@"../../../scores.csv");

        // Merge the data sources using a named type
        // var could be used instead of an explicit type
        IEnumerable<Student> queryNamesScores =
            from name in names
            let x = name.Split(',')
            from score in scores
            let s = score.Split(',')
            where x[2] == s[0]
            select new Student()
            {
                FirstName = x[0],
                LastName = x[1],
                ID = Convert.ToInt32(x[2]),
                ExamScores = (from scoreAsText in s.Skip(1)
                              select Convert.ToInt32(scoreAsText)).
                              ToList()
            };

        // Optional. Store the newly created student objects in memory
        // for faster access in future queries
        List<Student> students = queryNamesScores.ToList();

        foreach (var student in students)
        {
            Console.WriteLine("The average score of {0} {1} is {2}.",
                student.FirstName, student.LastName, student.ExamScores.Average());
        }

        //Keep console window open in debug mode
        Console.WriteLine("Press any key to exit.");
        Console.ReadKey();
    }
}
/* Output: 
    The average score of Adams Terry is 85.25.
    The average score of Fakhouri Fadi is 92.25.
    The average score of Feng Hanying is 88.
    The average score of Garcia Cesar is 88.25.
    The average score of Garcia Debra is 67.
    The average score of Garcia Hugo is 85.75.
    The average score of Mortensen Sven is 84.5.
    The average score of O'Donnell Claire is 72.25.
    The average score of Omelchenko Svetlana is 82.5.
    The average score of Tucker Lance is 81.75.
    The average score of Tucker Michael is 92.
    The average score of Zabokritski Eugene is 83.
 */

يمكن العثور على هذا المثال أيضاً في مقالة كيفية: تعبئة كائن مجموعات من مصادر متعددة (LINQ). لترجمة وتشغيل هذا المثال, اتبع الإرشادات الموجودة في هذه المقالة.

التحويل البرمجي للتعليمات البرمجية

  • قم بإنشاء المشروع Visual Studio الذي تستهدف الإصدار 3.5 من برنامج NET Framework. افتراضياً، يحتوي المشروع على مرجع إلى System.Core.dll والتوجيه using لمساحة الاسم System.Linq.

  • انسخ التعليمات البرمجية إلى مشروعك.

  • اضغط F5 للتحويل البرمجي للبرنامج وتشغيله.

  • اضغط أي مفتاح للخروج من نافذة وحدة التحكم.

راجع أيضًا:

المهام

كيفية القيام بما يلي: ترتيب نتائج جملة Join (دليل البرمجة لـ #C)

المرجع

جملة الربط (مرجع C#)

المبادئ

LINQ استعلام التعبيرات (C# البرمجة الدليل)

عمليات الانضمام