Usando o exemplo simples abaixo, qual é a melhor maneira de retornar resultados de várias tabelas usando o Linq para SQL?
Digamos que eu tenha duas tabelas:
Dogs: Name, Age, BreedId
Breeds: BreedId, BreedName
Eu quero devolver todos os cães com os deles BreedName
. Eu deveria ter todos os cães usando algo assim sem problemas:
public IQueryable<Dog> GetDogs()
{
var db = new DogDataContext(ConnectString);
var result = from d in db.Dogs
join b in db.Breeds on d.BreedId equals b.BreedId
select d;
return result;
}
Mas se eu quero cães com raças e tente isso, tenho problemas:
public IQueryable<Dog> GetDogsWithBreedNames()
{
var db = new DogDataContext(ConnectString);
var result = from d in db.Dogs
join b in db.Breeds on d.BreedId equals b.BreedId
select new
{
Name = d.Name,
BreedName = b.BreedName
};
return result;
}
Agora percebo que o compilador não me permite retornar um conjunto de tipos anônimos, pois espera Dogs, mas existe uma maneira de retornar isso sem ter que criar um tipo personalizado? Ou tenho que criar minha própria classe DogsWithBreedNames
e especificar esse tipo no select? Ou existe outra maneira mais fácil?
c#
linq
linq-to-sql
Jonathan S.
fonte
fonte
foreach (var cust in query) Console.WriteLine("id = {0}, City = {1}", cust.CustomerID, cust.City);
Respostas:
Eu costumo seguir esse padrão:
Isso significa que você tem uma classe extra, mas é rápido e fácil de codificar, facilmente extensível, reutilizável e seguro para o tipo.
fonte
Você pode retornar tipos anônimos, mas isso realmente não é bonito .
Nesse caso, acho que seria muito melhor criar o tipo apropriado. Se ele for usado apenas dentro do tipo que contém o método, torne-o um tipo aninhado.
Pessoalmente, eu gostaria que o C # recebesse "tipos anônimos nomeados" - ou seja, o mesmo comportamento dos tipos anônimos, mas com nomes e declarações de propriedades, mas é isso.
EDIT: Outros estão sugerindo o retorno de cães e, em seguida, acessando o nome da raça através de um caminho de propriedade etc. Essa é uma abordagem perfeitamente razoável, mas o IME leva a situações nas quais você fez uma consulta de uma maneira específica devido aos dados que deseja use - e essa meta-informação é perdida quando você apenas retorna
IEnumerable<Dog>
- a consulta pode estar esperando que você use (digamos), emBreed
vez deOwner
devido a algumas opções de carregamento etc., mas se você esquecer isso e começar a usar outras propriedades, seu aplicativo poderá funcionar, mas não tão eficientemente quanto você imaginou originalmente. Claro, eu poderia estar falando besteira, ou otimizando demais, etc ...fonte
Só para adicionar o valor de meus dois centavos :-) Eu aprendi recentemente uma maneira de lidar com objetos anônimos. Ele pode ser usado apenas ao direcionar a estrutura do .NET 4 e somente ao adicionar uma referência ao System.Web.dll, mas é bastante simples:
Para poder adicionar uma referência ao System.Web.dll, você deve seguir os conselhos do rushonerok : Verifique se a estrutura de destino do [projeto] é ".NET Framework 4" e não ".NET Framework 4 Client Profile".
fonte
Não, você não pode retornar tipos anônimos sem passar por alguns truques.
Se você não estava usando C #, o que você procuraria (retornando vários dados sem um tipo concreto) é chamado de Tupla.
Existem muitas implementações de tupla em C #, usando a mostrada aqui , seu código funcionaria assim.
E no site de chamada:
fonte
... select Tuple.Create(d, b)
.Você poderia fazer algo assim:
fonte
Você deve usar o
ToList()
método primeiro para obter linhas do banco de dados e, em seguida, selecionar itens como uma classe. Tente o seguinte:Então, o truque é o primeiro
ToList()
. É imediatamente faz a consulta e obtém os dados do banco de dados. O segundo truque é selecionar itens e usar o inicializador de objetos para gerar novos objetos com itens carregados.Espero que isto ajude.
fonte
No C # 7, agora você pode usar tuplas! ... o que elimina a necessidade de criar uma classe apenas para retornar o resultado.
Aqui está um código de exemplo:
Pode ser necessário instalar o pacote de nuget System.ValueTuple.
fonte
Agora percebo que o compilador não me permite retornar um conjunto de tipos anônimos, pois espera Dogs, mas existe uma maneira de retornar isso sem ter que criar um tipo personalizado?
Use use object para retornar uma lista de tipos anônimos sem criar um tipo personalizado. Isso funcionará sem o erro do compilador (no .net 4.0). Voltei a lista ao cliente e a analisei no JavaScript:
fonte
Basta selecionar os cães e, em seguida
dog.Breed.BreedName
, usar , isso deve funcionar bem.Se você tiver muitos cães, use DataLoadOptions.LoadWith para reduzir o número de chamadas de banco de dados.
fonte
Você não pode retornar tipos anônimos diretamente, mas pode fazer um loop através do método genérico. O mesmo acontece com a maioria dos métodos de extensão LINQ. Não há mágica lá, enquanto parece que eles retornariam tipos anônimos. Se o parâmetro for anônimo, o resultado também poderá ser anônimo.
Abaixo um exemplo baseado no código da pergunta original:
fonte
Bem, se você estiver retornando Dogs, você faria:
Se você deseja que o Breed seja carregado com antecedência e não com carregamento lento, basta usar a construção DataLoadOptions apropriada .
fonte
BreedId
naDog
tabela é obviamente uma chave estrangeira para a linha correspondente naBreed
tabela. Se você configurou seu banco de dados corretamente, o LINQ to SQL deve criar automaticamente uma associação entre as duas tabelas. A classe Dog resultante terá uma propriedade Breed e a classe Breed deve ter uma coleção Dogs. Ao configurá-lo dessa maneira, você ainda pode retornarIEnumerable<Dog>
, que é um objeto que inclui a propriedade de criação. A única ressalva é que você precisa pré-carregar o objeto de criação junto com os objetos de cachorro na consulta para que eles possam ser acessados após o descarte do contexto de dados e (como outro autor sugeriu) executar um método na coleção que fará com que o objeto consulta a ser executada imediatamente (neste caso, ToArray):É então trivial acessar a raça para cada cão:
fonte
Se a idéia principal é fazer com que a instrução SQL select enviada ao servidor de Banco de Dados tenha apenas os campos obrigatórios e nem todos os campos de Entidade, você poderá fazer isso:
fonte
Tente isso para obter dados dinâmicos. Você pode converter o código da Lista <>
fonte
Se você tem uma configuração de relacionamento no seu banco de dados com uma restrição de chave estrangeira no BreedId, você não entende isso já?
Agora eu posso ligar para:
E no código que chama isso:
Portanto, no seu exemplo, você chamaria algo como dog.Breed.BreedName - como eu disse, isso depende do seu banco de dados ser configurado com esses relacionamentos.
Como outros já mencionaram, o DataLoadOptions ajudará a reduzir as chamadas ao banco de dados, se isso for um problema.
fonte
Isso não responde exatamente à sua pergunta, mas o Google me levou aqui com base nas palavras-chave. É assim que você pode consultar um tipo anônimo em uma lista:
fonte