Este artigo foi traduzido por máquina.

Pontos de dados

Consultas de projeção do LINQ e alternativas nos Serviços WCF

Julie Lerman

Baixe o código de exemplo

Julie Lerman
O apresentador no meu grupo de usuários .NET local estava escrevendo uma consulta LINQ durante a sessão no mês passado quando perguntei-lo, “ como nunca vivemos sem LINQ? ” “ Tenho que não faz idéia ”, ele respondeu.

É verdade. Desde que foi apresentada no Visual Studio 2008, o LINQ fez tais uma diferença no como nós de código no Microsoft .NET Framework. Em combinação com muitos novos recursos de linguagem que foram introduzidos no Visual Basic e translation from VPE for Csharp, é um problema consistente o solver para consultar fontes de objetos e dados na memória.

Um dos recursos do LINQ que é um blessing e uma ocasional fonte de frustração são que ele pode projeto aleatoriamente em forma de dados em tipos anônimos. Quando você simplesmente precisar obter uma exibição especial dos seus dados, sem a necessidade de declarar uma nova classe para este tipo descartável, tipos anônimos são uma ótima solução. Projeções de LINQ e os tipos anônimos certamente tem estragou conosco. Então por que devo dizer que também podem ser uma fonte de frustração?

Se você nunca tiver usado uma projeção de LINQ em um método que precisa para retornar dados para outro método — ou pior, usados uma projeção de LINQ em uma operação de serviço do Windows Communication Foundation (WCF) — podem entender.

Como tipos anônimos são tipos descartável, eles têm nenhuma declaração e são compreendidos somente dentro do método onde eles são criados. Se você escrever uma consulta que retorna uma lista de tipos anônimos, não é possível definir um método ar gument dizer “ que vou retornar uma lista de … ” porque não há nenhuma forma para expressar “ … de tipos anônimos. ”

Aqui está uma consulta LINQ to Entities com uma projeção simples:

var custQuery = from c in context.Customers

                 select new {c.CustomerID, Name=c.LastName.Trim() + 

                 ", " + c.FirstName};

Em tempo de execução, a variável custQuery realmente irá ser um f__AnonymousType0 de <<>ObjectQuery <int,string> >.

O var (e o uso alternativo do Visual Basic Dim) nos permite escapar não ter (ou que precisam de) uma maneira de expressar este tipo não.

Se você desejar retornar os resultados dessa consulta de um método, a solução somente razoável é criar uma classe que representa o tipo que está sendo retornado. No entanto, dessa forma, processa a beleza de moot tipo anônimo. Agora você tem que escrever código mais, definem classes e (possivelmente) novos projetos para alojar as novas classes, verifique se os vários assemblies usando essas classes têm acesso a eles e assim por diante.

Até recentemente, os serviços de dados forneciam um conundrum adicional. Dados de projeto, você precisava criar uma operação personalizada em um serviço, execute sua própria consulta e retornar algum tipo de classe predefinido que pode ser entendida pelo cliente.

Quando você está trabalhando com os serviços, há muitos cenários em que deseja trabalhar com um determinado modo de exibição de dados sem pagando o preço de movimentação tipos maiores entre a transmissão.

Na verdade, há mais opções além de criar um tipo extra em seu domínio para atender a essa necessidade temporária.

Novo recurso de projeção no WCF Data Services

A atualização de serviços de dados para o .NET Framework 3.5 SP1 apresenta alguns recursos poderosos para serviços de dados do WCF, que também fazem parte do .NET Framework 4. Entre esses recursos é a capacidade de usar projeções em consultas com os serviços de dados. É altamente recomendável fazer o check-out WCF Data Services equipe postagem do blog em todos os que é nova nesta atualização de blogs.msdn.com/astoriateam/Archive/2010/01/27/Data-Services-Update-for-NET-3-5-SP1-Available-for-download.aspx.

O operador select $ foi adicionado a sintaxe de URI de serviços de dados. Ele permite propriedade e até mesmo projeção de propriedade de navegação.

Este é um exemplo simples de uma projeção obtém algumas propriedades escalares para um cliente junto com a propriedade de navegação SalesOrderHeaders:

http://localhost /DataService.svc/Customers(609)
  $select=CustomerID,LastName,FirstName,SalesOrderHeaders&$expand=
  SalesOrderHeaders

O operador de expansão força os resultados para incluir não apenas um link para pedidos, mas os dados para cada pedido também.

Figura 1 mostra os resultados desta consulta. O SalesOrderHeaders expandido (que contém somente uma única ordem) é realçado em amarelo enquanto as informações do cliente são realçadas em verde.

Figure 1 Results of a Data Services Query Projection Requesting Three Customer Properties and the Customer’s SalesOrder-Headers
Figura 1 Resultados de uma projeção de consulta Data Servicessolicitar três propriedades de cliente e SalesOrderHeaders do cliente

O LINQ to recurso REST no .NET Framework e APIs para os serviços WCF dados de cliente do Silverlight foi atualizado para permitir que as projeções assim:

var projectedCust = (from c in context.Customers

                    where c.CustomerID==609

                    select new {c.CustomerID, c.LastName})

                    .FirstOrDefault();

ProjectedCust agora é um tipo anônimo que pode uso em meu aplicativo de cliente.

Também é possível para o projeto em tipos de entidade conhecidos e, em alguns casos, o DataContext pode controlar as alterações feitas pelo cliente e essas alterações podem ser mantidas volta através SaveChanges método do serviço. Estar ciente de que todas as propriedades ausentes irão obter preenchidas com os padrões (ou nula se elas estiverem anuláveis) e ser persistida para o banco de dados.

Ativando projetados tipos fortes de um EDM

Se você estiver usando um Estrutura de Entidade Modelo de Dados de Entidade (EDM), há uma maneira conveniente de evitar sendo presos com tipos anônimos quando é necessário passá-los fora do método em que foram criados.

O EDM tiver um mapeamento chamado QueryView. Eu já apontada muitos clientes isso no passado, antes para o suporte de projeção de serviços de dados. Não apenas o ele resolve o problema bem para serviços de dados, mas para serviços WCF e serviços de RIA personalizados também.

O que é um QueryView? Ele é um tipo especial de mapeamento nos metadados do Estrutura de Entidade. Normalmente, você pode mapear as propriedades de uma entidade para tabelas de banco de dados ou exibir colunas como eles estão descritos no modelo de armazenamento — SSDL (Storage Schema Definition Language) — de metadados, como mostra a Figura 2.

Figure 2 Mapping Table Columns Directly to Entity Properties

Figura 2 Colunas de tabela de mapeamento diretamente para as propriedades da entidade

QueryView, entretanto, permite que você criar um modo de exibição por essas colunas da tabela SSDL em vez de mapa diretamente a eles. Há muitas razões para usar um QueryView. Alguns exemplos incluem: para expor suas entidades como lida - somente para entidades de filtro de forma condicional que não permite mapeamento ou para fornecer diferentes modos de exibição de tabelas de dados do banco de dados.

É a última dessas finalidades me concentrarei no como uma alternativa para os tipos anônimos que freqüentemente perceber que está projetando em seu aplicativo. Um exemplo seria uma lista. Por que retornar um tipo de cliente inteira para uma lista suspensa que necessita de apenas uma ID e o nome do cliente?

Criando um QueryView

Antes de criar um QueryView, você precisará criar uma entidade no modelo que representa a forma do modo de exibição que tanto deseja — por exemplo, a entidade CustomerNameAndID.

Mas você não pode mapear esta entidade diretamente à tabela clientes no SSDL. Mapeando a entidade Customer e entidade CustomerNameAndID para a coluna da tabela CustomerID criaria um conflito.

Em vez disso, mesmo modo que cria um modo de exibição de uma tabela do banco de dados, você pode criar um modo de exibição do cliente SSDL diretamente nos metadados. Um QueryView está literalmente uma expressão de Entidade SQL SSDL. De parte dos metadados do idioma (MSL) de especificação de mapeamento do modelo. Não há nenhum suporte de designer para criar QueryView, de modo que você precisará digite diretamente na XML.

Como você vai ser mapeando o esquema de armazenamento da tabela, ele uma boa idéia de ver o que parece. Figura 3 lista a descrição SSDL a tabela de banco de dados do cliente, se parece com a entidade Customer nos metadados do modelo conceitual, exceto para o uso de tipos de dados do provedor.

Figura 3 A descrição SSDL da tabela de banco de dados ao cliente

<EntityType Name="Customer">

  <Key>

    <PropertyRef Name="CustomerID" />

  </Key>

  <Property Name="CustomerID" Type="int" Nullable="false"

            StoreGeneratedPattern="Identity" />

  <Property Name="Title" Type="nvarchar" MaxLength="8" />

  <Property Name="FirstName" Type="nvarchar" Nullable="false" 

            MaxLength="50" />

  <Property Name="MiddleName" Type="nvarchar" MaxLength="50" />

  <Property Name="LastName" Type="nvarchar" Nullable="false" 

            MaxLength="50" />

  <Property Name="Suffix" Type="nvarchar" MaxLength="10" />

  <Property Name="CompanyName" Type="nvarchar" MaxLength="128" />

  <Property Name="SalesPerson" Type="nvarchar" MaxLength="256" />

  <Property Name="EmailAddress" Type="nvarchar" MaxLength="50" />

  <Property Name="Phone" Type="nvarchar" MaxLength="25" />

  <Property Name="ModifiedDate" Type="datetime" Nullable="false" />

  <Property Name="TimeStamp" Type="timestamp" Nullable="false"

            StoreGeneratedPattern="Computed" />

</EntityType>

Outro importante elemento para o QueryView será namespace do esquema de armazenamento, ModelStoreContainer. Agora você tem as partes necessárias para criar a expressão QueryView. Aqui está um QueryView que projetos a três necessários campos o SSDL para a entidade CustomerNameAndID que criei no modelo:

SELECT VALUE AWModel.CustomerNameAndID(c.CustomerID, c.FirstName, 

        c.LastName) FROM ModelStoreContainer.Customer as c

Convertendo Entidade SQL para o inglês: “ Consultar o cliente no esquema do armazenamento, retire essas três colunas e devolva-os para mim como uma entidade CustomerNameAndID. ” AWModel é o espaço para nome de recipiente de entidade do modelo conceitual. É necessário que você use os nomes com rigidez de tipos dos tipos a CSDL (Conceptual Schema Definition Language) e o SSDL referenciados na expressão.

Enquanto os resultados da projeção (um número inteiro, uma seqüência de caracteres e uma string) corresponde ao esquema da entidade de destino, o mapeamento será bem-sucedida. Tentei usar as funções e concatenação dentro a projeção — por exemplo, (c.CustomerID, c.FirstName + c.LastName)—but isso falhar com um erro indicando que as funções não são permitidas. Assim, eu estou forçado a usar as propriedades nome e sobrenome e permitem que o cliente de lidar com a concatenação.

Colocando o QueryView nos metadados

Você deve colocar a expressão QueryView dentro do elemento EntitySetMapping para a entidade que vai dentro EntityContainerMapping nos metadados. Figura 4 mostra o XML bruto do meu arquivo EDMX este QueryView (realçado em amarelo).

Figure 4 A QueryView in the Mappings Section

Figura 4 Um QueryView na seção mapeamentos

Agora meu CustomerNameAndID faz parte do meu modelo e estará disponível para qualquer consumidor. E há uma outra vantagem para o QueryView. Embora o objetivo deste QueryView criar uma lista de referência somente leitura, você também pode atualizar entidades que são mapeadas usando QueryViews. O contexto irá rastrear alterações em objetos CustomerNameAndID. Embora Estrutura de Entidade não seja capaz de gerar automaticamente inserir, atualizar e excluir comandos para esta entidade, você pode mapear procedimentos armazenados nele.

Colhendo os benefícios da QueryView

Agora que possui o QueryView no modelo, você Don precisa depender projeções ou tipos anônimos para recuperar esses modos de exibição de seus dados. Em serviços de dados do WCF, CustomerNameAndIDs se torna um conjunto de entidade válida para consulta, como mostrado aqui:

List<CustomerNameAndID> custPickList = 

  context.CustomerNameAndIDs.ToList();

Não há projeções confusas. Melhor ainda, você pode criar operações de serviço em seus serviços WCF personalizados que agora podem retornar esse objeto com rigidez de tipos sem ter que definir novos tipos no seu aplicativo e o projeto neles.

public List<CustomerNameAndID> GetCustomerPickList()

    {

      using (var context = new AWEntities())

      {

        return context.CustomerNameAndIDs.OrderBy(

          c => c.LastName).ToList();

      }

    }

Devido a limitação que impede que nós concatenando os nomes e sobrenomes no QueryView, é para os desenvolvedores que consumam o serviço para fazer essa concatenação em sua extremidade.

Serviços do WCF RIA também pode aproveitar o QueryView. É aconselhável para expor um método para recuperar uma lista restaurante do seu serviço de domínio. Em vez de ter de criar uma classe extra no serviço de domínio para representar as propriedades projetadas, esta entidade RestaurantPickList respalda um QueryView no modelo, o que torna fácil fornecer esses dados:

public IQueryable<RestaurantPickList> GetRestaurantPickList()

    {

      return context.RestaurantPickLists;

    }

QueryViews ou projeções — você tem coberta

Ter a capacidade de modos de exibição de projeto sobre seus tipos de dados é um enorme benefício de consulta e é um importante acréscimo ao WCF Data Services. Mesmo assim, há momentos ao ter acesso a esses modos de exibição, sem a necessidade de projeto e sem precisar se preocupar sobre o resultado de compartilhamento simplificará algumas das tarefas de codificação.

Uma última Observação: Com a introdução de chaves externas na versão 4 do .NET Framework do Estrutura de Entidade, QueryView escolha make listas até mesmo mais sentido porque você pode retornar entidades somente leitura e simplesmente usar suas propriedades para atualizar propriedades de chave externas nas entidades que você está editando.  

Julie Lerman é um MVP da Microsoft, .NET mentor e consultor em montanhas de Vermont. Você pode encontrar a sua apresentação sobre acesso a dados e outros tópicos do Microsoft .NET em grupos de usuários e conferências em todo o mundo. Lerman bloga em thedatafarm.com/blog e é autor do livro altamente aclamado pacote, “ Programming Estrutura de Entidade ” (O’Reilly Media, 2009). Execute no Twitter: julielerman.

Graças ao especialista técnico seguir para revisar este artigo: Alex James