Como: executar operações de associação personalizado (guia de programação do 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 está limitada a, e otimizado para, digite de equijoins, que são de longe mais comuns da operação join.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 apresentar 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çã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 JOIN (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 criação de seqüências de código-fonte em relação à qual as 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 a 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 da cláusula join propriamente dito.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 da chamada do método repetidas.No entanto, como join é otimizado, neste caso específico, 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 projeto de aplicativo de console que atinge .NET Framework 3.5 ou posterior.Por padrão, o projeto tem uma referência a System.Core.dll e um using diretriz 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
Como: ordem dos resultados de uma cláusula de associação (guia de programação do C#)
Referência
cláusula JOIN (referência de C#)