Archive for August 2011

EF Code First-Acessando Stored Procedures

Olá,

Vou iniciar este post informando que o Entity Framework Code First não tem suporte nativo para Stored Procedures, ainda!!!

Mas se não é suportado nativamente, então como é possível acessá-las ? Através do método SqlQuery() do contexto, mas existe um inconveniente: o acesso fica vinculado ao banco de dados, ou seja, para cada banco de dados o acesso é feito de uma maneira, mesmo porquê cada banco tem uma maneira específica de chamar e tratar os parâmetros das stored procedures.

Em nosso exemplo vamos demonstrar como acessar uma stored procedure do banco de dados NorthWind. A procedure que vamos utilizar é a CustOrderHist, que recebe como parâmetro o código do cliente e retorna os produtos e quantidades compradas pelo cliente.

Vamos então criar nosso projeto console no Visual Studio 2010 e já adicionar as referências para o EF CodeFirst, caso você não tenha o EF CodeFirst instalado em seu computador, pode baixá-lo aqui.

image

Para pegar o retorno da stored procedure, vamos criar uma classe que conterá os campos retornados:

   1: public class ProdutosPorCliente

   2: {

   3:     public string ProductName { get; set; }

   4:     public int Total { get; set; }

   5: }

Para obter o conteúdo da classe, você precisa verificar o que a stored procedure retorna e neste caso ela retorna os nomes dos produtos e a quantidade comprada.

Antes de criar nosso contexto, vamos criar o arquivo de configuração para a string de conexão, veja este post sobre strings de conexão.

   1: <?xml version="1.0" encoding="utf-8" ?>

   2: <configuration>

   3:   <connectionStrings>

   4:     <add name="Contexto" providerName="System.Data.SqlClient" connectionString="Data Source=(local);Initial Catalog=Northwind;Persist Security Info=True;User ID=teste;Password=teste;Pooling=False;MultipleActiveResultSets=true;" />

   5:   </connectionStrings>

   6: </configuration>

Agora vamos criar o nosso contexto e incluir a chamada para a stored procedure:

   1: class Contexto : DbContext

   2: {

   3:     public IEnumerable<ProdutosPorCliente> RetornaProdutosPorCliente(string codigoCliente)

   4:     {

   5:         SqlParameter parClienteID = new SqlParameter("@CustomerID", SqlDbType.Text);

   6:         parClienteID.Value = codigoCliente;

   7:  

   8:         return Database.SqlQuery<ProdutosPorCliente>("exec CustOrderHist @CustomerID", parClienteID);

   9:     }

  10: }

Veja que nosso contexto não possui as classes de dados, mas elas foram omitidas somente por uma questão didática.

O inconveniente aqui, como falamos no início é que a chamada da stored procedure fica vinculada ao banco de dados. No exemplo usamos SqlParameter() para criar o parâmetro, pois nosso banco de dados é SQL Server. Caso o banco seja diferente a classe de parâmetro muda.

Vamos agora ao exemplo para realizar a chamada ao método:

   1: static void Main(string[] args)

   2:         {

   3:             Contexto ctx = new Contexto();

   4:  

   5:             var retProc = ctx.RetornaProdutosPorCliente("VINET");

   6:  

   7:             foreach (var l in retProc)

   8:             {

   9:                 Console.WriteLine("{0} - {1}", l.ProductName, l.Total);

  10:             }

  11:         }

Veja que é bem simples, pois o método retorna um IEnumerable que pode ser percorrido por um foreach().

Espero que o exemplo seja útil, mas gostaria de deixar claro que este é somente um meio alternativo para acessar stored procedures.

Até a próxima,

Carlos dos Santos.

EF CodeFirst–Gerenciando as Strings de Conexão

Olá,

Hoje vamos falar um pouco sobre o gerenciamento de string de conexões no Entity Framework Code First, uma maneira muito simples e rápida de criar um mapeamento objeto relacional em C# com o Visual Studio 2010.

Se você ainda não conhece o EF CodeFirst, veja este post e também o Blog do time de ADO.Net.

O que vou tratar neste post é como podemos armazenar as strings de conexão e os providers que permitem o acesso do EF ao nosso banco de dados. Por padrão, quando criamos um contexto para nosso EF, é necessário uma string de conexão e um Data Provider, que indica qual o banco de dados será utilizado, mas se criarmos um contexto simples, sem nenhuma string de conexão, como no exemplo abaixo, o que acontece ?

 1: using System;

 

 2: using System.Collections.Generic;

 

 3: using System.Linq;

 

 4: using System.Text;

 

 5: using System.Data.Entity;

 

 6:

 

 7: namespace EFExemplo

 

 8: {

 

 9:     public class ContextoExemplo : DbContext

 

 10:     {

 

 11:         public DbSet<Cliente> Cliente { get; set; }

 

 12:     }

 

 13: }

 

Como não expecificamos nenhum construtor, o EF tentará usar o servidor .SQLExpress e tentará criar o banco de dados ContextoExemplo e caso você não tenha este servidor SQL disponível, receberá um erro.

Vamos imaginar que você queira especificar uma string de conexão, neste caso temos várias maneiras de fazer isto e vamos explorar cada uma delas:

Opção 1: Informar a string de conexão no construtor do contexto:

 1: public class ContextoExemplo : DbContext

 

 2:     {

 

 3:         public DbSet<Cliente> Cliente { get; set; }

 

 4:

 

 5:         public ContextoExemplo(string conexao) : base(conexao)

 

 6:         {

 

 7:

 

 8:         }

 

 9:     }

 

Neste caso podemos usar de duas maneiras: você pode informar somente a string de conexão e neste caso poderá usar somente o SQL Server, que é o provider default para o EF. Isto pode ser feito na instância do contexto:

 1: static void Main(string[] args)

 

 2: {

 

 3:     ContextoExemplo ctx = new ContextoExemplo("data source=(local); initial catalog=EFExemplo; user id=teste; password=teste;");

 

 4:     ctx.Database.CreateIfNotExists();

 

 5: }

 

Neste caso será criado o banco de dados EFExemplo no servidor SQL local.

Opção 2: Informar o noem de uma string armazenada em um arquivo de configuração:

A segunda maneira é você manter a string fora do executável, de maneira que você possa modificá-la a qualquer momento, neste caso usaremos o arquivo de configuração da aplicação (app.config ou web.config):

 1: <?xml version="1.0" encoding="utf-8" ?>

 

 2: <configuration>

 

 3:   <connectionStrings>

 

 4:     <add name="EFExemplo" providerName="System.Data.SqlClient" connectionString="data source=(local); initial catalog=EFExemplo; user id=teste; password=teste;"/>

 

 5:     <add name="EFExemplo-MySql" connectionString="Server=localhost;Database=efexemplo;Uid=teste;Pwd=teste;Port=3306;" providerName="MySql.Data.MySqlClient"/>

 

 6:   </connectionStrings>

 

 7: </configuration>

 

No arquivo de configuração podemos agora manter mais de uma string e também informar qual o banco de dados de cada conexão. Para usar a conexão, basta informá-la no construtor:

 1: ContextoExemplo ctx = new ContextoExemplo("EFExemplo");

 

ou

 1: ContextoExemplo ctx = new ContextoExemplo("EFExemplo-MySql");

 

 

Opção 2: Informar um DbConnection:

DBConnection é a classe que cria as conexões para o EF CodeFirst, neste caso você pode gerar a string de uma maneira mais dinâmica e ela não precisa estar armazenada em um arquivo app.config ou web.config, o que deixaria a string mais exposta. Este mecanismo é interessante quando você quer criptografar a string, veja:

 1: public class ContextoExemplo : DbContext

 

 2: {

 

 3:     public DbSet<Cliente> Cliente { get; set; }

 

 4:

 

 5:     public ContextoExemplo(string conexao) : base(conexao)

 

 6:     {

 

 7:

 

 8:     }

 

 9:

 

 10:     public ContextoExemplo(DbConnection conexao) : base(conexao,true)

 

 11:     {

 

 12:

 

 13:     }

 

 14: }

 

Veja que agora temos uma sobrecarga do construtor, onde informamos o DbConnection e vamos fazer isto na instância do contexto:

 1: static void Main(string[] args)

 

 2: {

 

 3:     DbProviderFactory prov = DbProviderFactories.GetFactory("System.Data.SqlClient");

 

 4:     DbConnection conexao = prov.CreateConnection();

 

 5:     conexao.ConnectionString = "data source=(local); initial catalog=EFExemplo; user id=teste; password=teste;";

 

 6:

 

 7:     ContextoExemplo ctx = new ContextoExemplo(conexao);

 

 8:     ctx.Database.CreateIfNotExists();

 

 9: }

 

Para criarmos a conexão, primeiro precisamos identificar o tipo do banco de dados, através do DbProviderFactory() e logo a seguir, informamos a string de conexão que é depois passada como parâmetro para o contrutor do contexto. Note que a string de conexão poderia vir de um arquivo criptografado ou mesmo de um serviço web, o que aumentaria a segurança da aplicação.

Bem pessoal, espero que este post possa lhes ser útil.

Até breve,

Carlos dos Santos.