How to: Executar operações de associação de Personalizar (guia de programação de C#)

Este exemplo mostra como executar operações de associação que não são possíveis com o join cláusula. Em uma expressão de consulta, o join cláusula é limitada a e otimizada para equijoins, que são de longe o tipo mais comum de operação de associação. Ao realizar uma equijoin, você provavelmente sempre obter o melhor desempenho usando o join cláusula.

No entanto, o join cláusula não pode ser usada nos seguintes casos:

  • Quando a associação está vinculada em uma expressão de desigualdade (um não-equijoin).

  • Quando a associação depende mais de uma expressão de igualdade ou desigualdade.

  • Quando você tem que introduzir uma variável de intervalo temporário para a seqüência da direita (interno) antes da operação de associação.

Para realizar associações que não são equijoins, você pode usar várias from cláusulas apresentar cada fonte de dados de forma independente. Em seguida, aplicar uma expressão de predicado em um where cláusula para a variável de intervalo para cada fonte. A expressão também pode assumir a forma de uma chamada de método.

ObservaçãoObservação

Não confunda esse tipo de operação de associação personalizado com o uso de vários from cláusulas para acessar coleções internas. Para obter mais informações, consulte cláusula deunir (referência de C#).

Exemplo

O primeiro método no exemplo a seguir mostra uma junção cruzada simple. Junções cruzadas devem ser usadas com cautela, porque elas podem produzir conjuntos de resultados muito grande. No entanto, elas podem ser úteis em algumas situações para criar seqüências de origem que consultas adicionais que são executadas.

O segundo método produz uma seqüência de todos os produtos cujo ID da categoria está listado na lista Categoria à esquerda. Observe o uso da let cláusula e o Contains método para criar uma matriz temporária. Também é possível criar a matriz antes da consulta e eliminar o primeiro from cláusula.

     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.
      */

No exemplo a seguir, a consulta deve associar-se duas seqüências com base na correspondência de chaves que, no caso da seqüência interna (lado direito), não podem ser obtidas antes a cláusula de associação. Se esta associação foram realizada com um join cláusula, em seguida, a Split método teria de ser chamado para cada elemento. O uso de vários from cláusulas permite que a consulta evitar a sobrecarga de chamada do método repetido. No entanto, como join é otimizado, nesse caso específico, ainda pode ser mais rápido do que o uso de várias from cláusulas. Os resultados irão variar dependendo principalmente a chamada de método é como cara.

class MergeTwoCSVFiles
{
    static void Main()
    {
        // See section Compiling the Code for information about the data files.
        string[] names = System.IO.File.ReadAllLines(@"../../../names.csv");
        string[] scores = System.IO.File.ReadAllLines(@"../../../scores.csv");

        // Merge the data sources using a named type.
        // You could use var instead of an explicit type for the query.
        IEnumerable<Student> queryNamesScores =
            // Split each line in the data files into an array of strings.
            from name in names
            let x = name.Split(',')
            from score in scores
            let s = score.Split(',')
            // Look for matching IDs from the two data files.
            where x[2] == s[0]
            // If the IDs match, build a Student object.
            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();
    }
}

class Student
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public int ID { get; set; }
    public List<int> ExamScores { get; set; }
}

/* Output: 
    The average score of Omelchenko Svetlana is 82.5.
    The average score of O'Donnell Claire is 72.25.
    The average score of Mortensen Sven is 84.5.
    The average score of Garcia Cesar is 88.25.
    The average score of Garcia Debra is 67.
    The average score of Fakhouri Fadi is 92.25.
    The average score of Feng Hanying is 88.
    The average score of Garcia Hugo is 85.75.
    The average score of Tucker Lance is 81.75.
    The average score of Adams Terry is 85.25.
    The average score of Zabokritski Eugene is 83.
    The average score of Tucker Michael is 92.
 */

Compilando o código

  • Criar um Visual Studio que destinos de projeto de aplicativo de console .NET Framework 3.5 ou posterior. Por padrão, o projeto tem uma referência a System.Core.dll e um using a diretiva para o namespace System. LINQ.

  • Substituir o Program a classe com o código do exemplo anterior.

  • Siga as instruções de Como: Associar-se o conteúdo de arquivos diferentes (LINQ) para configurar os arquivos de dados, scores.csv e names.csv.

  • Pressione F5 para compilar e executar o programa.

  • Pressione qualquer tecla para sair da janela do console.

Consulte também

Tarefas

How to: Ordem dos Resultados de uma cláusula de associação (guia de programação de C#)

Referência

cláusula deunir (referência de C#)

Conceitos

LINQ Expressões de consulta (guia de programação de C#)

Operações JOIN

Histórico de alterações

Date

History

Motivo

Agosto de 2010

Alterado o segundo exemplo, para que seja mais fácil de executar.

Aprimoramento de informações.