LINQ to SQL - Criando e usando um DataContext


Pode parecer estranho eu estar tocando no assunto LINQ to SQL , quando ainda não se tem uma posição oficial sobre a sua continuidade. Pessoalmente eu creio que mesmo que for descontinuado ainda haverá uma tempo onde a compatibilidade com outro recurso, provavelmente o Entity Framework, será mantida.

De qualquer forma os conceitos abordados referem-se ao LINQ e não serão totalmente descartados. Vou falar sobre o DataContext e neste sentido você pode fazer um paralelo com o Context do Entity Framework.

Um Data Context é um objeto do tipo System.Data.Linq.DataContext que suporta a atualização e manutenção de um banco de dados para objetos conhecidos do LINQ efetuando o tratamento da conexão do banco de dados, dessa forma ,para acessar as tabelas de um banco de dados elas devem estar mapeadas e disponíveis em um objeto Data Context.

Vamos trabalhar neste artigo usando como um banco de dados hipotético chamado Exemplo.mdf e duas tabelas Exemplo e Salario.

A estrutura do banco de dados e do arquivo Data Context é mostrado a seguir:

Para gerar o Data Context usando o assistente clique com o botão direito do mouse sobre o nome do projeto e selecione Add New Item;

A seguir selecione o Template LINQ to SQL Classes e informe onome ExemploDataContext.dbml e clique no botão Adicionar;

A seguir a partir da janela DataBase Explorer selecione as duas tabelas do banco de dados Exemplo.mdf e arraste para o descritor LINQ to SQL;

Pronto com isso temos o DataContext - ExemploDataContext - criado e pronto para usar nos exemplos a seguir.

Você pode tornar as tabelas de um banco de dados que deseja acessar disponíveis de duas formas:

DataContext ExemploDataContext = new DataContext(connString);
Table<Exemplo> Exemplo = ExemploDataContext.GetTable<Exemplo>();

No código acima criamos um Data Context chamado ExemploDataContext e uma coleção Table: Exemplo (para uma tabela Exemplo de um banco de dados), disponível naquel contexto.

Uma nova classe coleção generic, Table<T> , existente no namespace System.Data.Linq é usada para representar as tabelas de um banco de dados. Ela implementa as interfaces IEnumerable<T> e IQueryable<T> e ITable que por sua vez implementa IEnumerable
and
IQueryable.

Usamos também o método GetTable<T> do Data Context para criar um objeto Exemplo do tipo Table<Exemplo> no contexto ExemploDataContext.

O argumento do construtor DataContext é a string de conexão, a mesma que você com ADO .NET. Abaixo temos um exemplo de uma string e conexão para acessar um banco de dados chamado Exemplo:

String connString = @" Data Source=.;Initial Catalog=Exemplo;Integrated Security=True";

Como resultado temos que o nosso banco de dados passa a ser conhecido para o LINQ como ExemploDataContext e a tabela Exemplo passa a ser conhecida como o objeto Exemplo.

Uma forma mais elegante e recomenda de usar o Data Context é usar um Data Context fortemente tipado conforme o exemplo abaixo:

public partial class ExemploDataContext : DataContext
{
    public Table<Exemplo> Exemplo;
    public ExemploDataContext(String connString) : base(connString) {}
}

- Neste exemplo eu declarei a classe ExemploDataConext que representa um Data Context que possui um campo , Exemplo , para o a tabela Exemplo do banco de dados;

- O construtor chama o construtor base DataContext com a string de conexão;

- Para usar o contexto fortemente tipado, foi criada uma instância do mesmo realizando um consulta como :
ExemploDataContext exemplo = new ExemploDataContext(connString);

-Neste caso nosso banco de dados é visto pelo LINQ como objeto exemplo e a tabela Exemplo conhecida como Exemplo;

- A partir dai podemos codificar os objetos LINQ para fazer tudo oque precisamos para o LINQ gerenciar a tabela Exemplo do banco de dados como uma coleção Exemplo.

A seguir temos um exemplo onde estamos efetuando a consulta a tabela Exemplo do banco de dados Exemplo.mdf usando os objetos LINQ em memória. Note que para isso precisamos primeiro instanciar um objeto DataContext:

using System;
using System.Linq;
namespace LINQ_DataContext
{
	class Program
	{
		public static void Main(string[] args)
		{
			Console.WriteLine("Efetuando uma consulta LINQ");
			
			ExemploDataContext exemplo = new ExemploDataContext();
			      var consulta = from p in exemplo.Exemplo
					      from s in exemplo.Salario
					      where p.ID == s.ID
					      select new { p.Nome,s.Salario };
                           
			foreach(var linha in consulta)
			{
				Console.WriteLine("Nome  : {0}  ", linha.Nome );
				Console.WriteLine("Salario: {0}  ", linha.Salario);
			}
			Console.Write("Pressione algo para continuar . . . ");
			Console.ReadKey(true);
		}
	}
}

Neste exemplo estamos consultando os dados de duas tabelas : Exemplo e Salario usando o Data Context como um canal pelo qual efetuamos uma consulta LINQ para consultar o banco de dados e o resultado é retornado em objetos na memória.

Por trás dos panos a classe DataContext transforma a consulta LINQ em uma consulta SQL para visualizar a consulta SQL enviada ao banco de dados podemos usar a propriedade Log da classe Data Context :

Veja abaixo o mesmo exemplo usando a propriedade Log que redireciona o log para o console:

using System;
using System.Linq;
namespace LINQ_DataContext
{
	class Program
	{
		public static void Main(string[] args)
		{
		        Console.WriteLine("Efetuando uma consulta LINQ");
			
		        ExemploDataContext exemplo = new ExemploDataContext();

                      exemplo.Log = Console.Out;

		      var consulta = from p in exemplo.Exemplo
          			                  from s in exemplo.Salario
                    	                               where p.ID == s.ID
	  	                               select new { p.Nome, s.Salario };
                           
			foreach(var linha in consulta)
			{
				Console.WriteLine("Nome  : {0}  ", linha.Nome );
				Console.WriteLine("Salario: {0}  ", linha.Salario);
			}
			Console.Write("Pressione algo para continuar . . . ");
			Console.ReadKey(true);
		}
	}
}

Existe uma outra maneira de verificar a consulta SQL enviada pelo LINQ que é através do método GetCommand do DataContext que permite visualizar as instruções SELECT.

Este método requer a consulta LINQ como um argumento e retorna um objeto da classe DBCommand e você pode usar a sua propriedade CommandText para retornar o comando SQL usado pelo LINQ to SQL para retornar os registros do banco de dados.

Por outro lado o método GetChangeSet é usado para as instruções INSERT, UPDATE E DELETE, ele retorna um objeto da classe ChangeSet que contém as propriedades Inserts, Updates e Deletes. Elas dão acesso a uma lista de objetos que é alterada depois que um objeto associado a tabela do banco de dados é modificada.

Veja a seguir a utilização destes comandos no mesmo exemplo assim:

using System;
using System.Linq;
namespace LINQ_DataContext
{
	class Program
	{
		public static void Main(string[] args)
		{
			Console.WriteLine("Efetuando uma consulta LINQ");
			
			ExemploDataContext exemplo = new ExemploDataContext();

	              var consulta = from p in exemplo.Exemplo
        			              from s in exemplo.Salario
			              where p.ID == s.ID
		                          select new { p.Nome, s.Salario };
                           
                                       Console.WriteLine(exemplo.GetCommand(query).CommandText);
		          Console.WriteLine();
                          
			foreach(var linha in consulta)
			{
				Console.WriteLine("Nome  : {0}  ", linha.Nome );
				Console.WriteLine("Salario: {0}  ", linha.Salario);
			}
		         Exemplo exemplo = new Exemplo();
  		          exemplo.ID = 10;
		         exemplo.Nome = "Macoratti";
		         exemplo.Exemplo. InsertOnSubmit (exemplo);
		         Console.WriteLine();
		         Console.WriteLine(exemplo.GetChangeSet().ToString());

			Console.Write("Pressione algo para continuar . . . ");
			Console.ReadKey(true);
		}
	}
}

Neste exemplo temos que o objeto ChangeSet contém um objeto inserido; através da propriedade Inserts você pode acessar o novo objeto Exemplo incluído a coleção Exemplo através do método InsertOnSubmit.

Lembre-se que até o momento o banco de dados não foi sensibilizado para isso devemos usar o método SubmitChanges conforme abaixo:

using System;
using System.Linq;
namespace LINQ_DataContext
{
	class Program
	{
		public static void Main(string[] args)
		{
			Console.WriteLine("Efetuando uma consulta LINQ");
			
			ExemploDataContext exemplo = new ExemploDataContext();

	              var consulta = from p in exemplo.Exemplo
        	               	             from s in exemplo.Salario
			             where p.ID == s.ID
		                          select new { p.Nome, s.Salario };
                           
                                       Console.WriteLine(exemplo.GetCommand(query).CommandText);
		          Console.WriteLine();
                          
			foreach(var linha in consulta)
			{
				Console.WriteLine("Nome  : {0}  ", linha.Nome );
				Console.WriteLine("Salario: {0}  ", linha.Salario);
			}
	                   Exemplo exemplo = new Exemplo();
      		         exemplo.ID = 10;
		         exemplo.Nome = "Homem Aranha";
		         exemplo.Exemplo. InsertOnSubmit (exemplo);
		         Console.WriteLine();
		         Console.WriteLine(exemplo.GetChangeSet().ToString());

                       exemplo.SubmitChanges()

			Console.Write("Pressione algo para continuar . . . ");
			Console.ReadKey(true);
		}
	}
}

Dessa forma efetuamos uma revisão sobre o DataContext do LINQ to SQL e suas principais características. Até o presente momento ele continua sendo uma boa alternativa para acessar e efetuar o mapeamento objeto relacional quando estamos usando um banco de dados SQL Server.

Eu sei é apenas LINQ to SQL, mas eu gosto...


José Carlos Macoratti