Banco de Dados - SQL Server
Trabalhando com CLR: Stored Procedure – Primeiro passo
Depois de uma breve introdução sobre SQL CLR, para a nossa primeira funcionalidade, vamos tratar das Stored Procedure (procedimento armazenado), que podem ser utilizadas basicamente para retornar valores, várias consultas e/ou manipular dados no SQL Server.
por Paulo Roberto Pereira JuniorDepois de uma breve introdução sobre SQL CLR, para a nossa primeira funcionalidade da série de artigos sobre SQL CLR, vamos tratar das Stored Procedure (procedimento armazenado), que podem ser utilizadas basicamente para retornar valores, várias consultas e/ou manipular dados no SQL Server.
Depois de criado o projeto SQL CLR, para criarmos uma Stored Procedure com CLR, nós precisaremos adicionar um novo item (“New Item...” ou “Stored Procedure...”) no projeto, determinando também as características básicas deste item, como o nome do arquivo e o template, no casso “Stored Procedure”.
Já com a Stored Procedure adicionada no projeto, partimos para o código da nossa primeira funcionalidade, que é basicamente imprimir um texto qualquer nas mensagens de notificação (como uma chamada ao comando PRINT do SQL).
using System; using System.Data; using System.Data.SqlClient; using System.Data.SqlTypes; using Microsoft.SqlServer.Server;
public partial class StoredProcedures { [SqlProcedure] public static void Primeiro() { SqlContext.Pipe.Send("SQL From Hell!!!"); } }; |
E adicionamos o seguinte comando SQL no arquivo script de teste do projeto para executar nossa Stored Procedure.
EXEC Primeiro |
Mais informações sobre DEBUG de projetos SQL CLR:
http://sqlfromhell.wordpress.com/2009/10/03/debug-clr
Após o Debug (F5), podemos validar o resultado na caixa de Output do Visual Studio.
O segundo passo para desenvolver nosso procedimento armazenado é a criação de parâmetros, que basicamente consiste na criação de novos parâmetros no método.
using System; using System.Data; using System; using System.Data; using System.Data.SqlClient; using System.Data.SqlTypes; using Microsoft.SqlServer.Server;
public partial class StoredProcedures { [SqlProcedure] public static void Primeiro(SqlString texto) { SqlContext.Pipe.Send(texto.ToString()); } }; |
EXEC Primeiro "SQL From Hell!!!" |
E após o deploy deste procedimento armazenado, percebemos que o nome do método (ex.: “Primeiro”) também será o nome do procedimento armazenado no banco de dados, assim como os argumentos.
A possibilidade de criarmos sobrecargas uma procedure (dois ou mais métodos com mesmo nome, mas como parâmetros distintos) não é permitida pelo SQL Server, mesmo que seja possível gerar um assembly compilável. Desta forma é recomendado definir nomes adequados para os nomes dos métodos para que não se repitam.
Mas para não ser necessário alterar os nomes dos métodos podemos determinar os nomes das procedures, simplesmente pela customização do atributo SqlProcedure, conforme o exemplo:
using System; using System.Data; using System.Data.SqlClient; using System.Data.SqlTypes; using Microsoft.SqlServer.Server;
public partial class StoredProcedures { [SqlProcedure(Name = "USP_Primeiro")] public static void Primeiro(SqlString texto) { SqlContext.Pipe.Send(texto.ToString()); } }; |
EXEC USP_Primeiro "SQL From Hell!!!" |
Que se refletirá no banco de dados, sem necessidade de customização do script SQL de deploy do projeto CLR, conforme demonstrado abaixo:
Mais informações sobre Deploy de projetos SQL CLR:
http://sqlfromhell.wordpress.com/2010/05/15/publicando-assemblies-clr-no-sql-server-pelo-visual-studio
Assim como podemos customizar o nome dos procedimentos armazenados, também é possível customizar algumas características dos parâmetros do método por meio de atributos (ex.: SqlFacet), conforme demonstrada abaixo a definição da quantidade máxima de 40 caracteres do parâmetro “texto”:
using System; using System.Data; using System.Data.SqlClient; using System.Data.SqlTypes; using Microsoft.SqlServer.Server;
public partial class StoredProcedures { [SqlProcedure(Name = "USP_Primeiro")] public static void Primeiro ([SqlFacet(MaxSize = 40)]SqlString texto) { SqlContext.Pipe.Send(texto.ToString()); } };
|
EXEC USP_Primeiro "SQL From Hell!!!" |
E como resultado, novamente sem qualquer customização no script SQL de deploy:
Desta forma, também será possível tratar as características dos tipos decimais (ou numéricos), como no exemplo que determinamos um parâmetro decimal de tamanho 10 (precisão), tendo duas casas após a vírgula (escala).
using System; using System.Data; using System.Data.SqlClient; using System.Data.SqlTypes; using Microsoft.SqlServer.Server;
public partial class StoredProcedures { [SqlProcedure(Name = "USP_Primeiro")] public static void Primeiro ([SqlFacet(Precision = 10, Scale = 2)]SqlDecimal valor) { SqlContext.Pipe.Send(valor.ToString()); } }; |
EXEC USP_Primeiro 12345678.90 |
Após o deploy, os valores determinados pelos atributos estarão refletidos no banco de dados, sem qualquer intervenção direta do desenvolvedor no script SQL:
Outras características também podem ser trabalhadas com os atributos, como atributos que recebem valores do procedimento armazenado (OUTPUT):
using System; using System.Data; using System.Data.SqlClient; using System.Data.SqlTypes; using Microsoft.SqlServer.Server;
public partial class StoredProcedures { [SqlProcedure(Name = "USP_Primeiro")] public static void Primeiro (out SqlString texto) { texto = new SqlString("Executado"); } }; |
DECLARE @VAR NVARCHAR(4000) EXEC USP_Primeiro @VAR OUT PRINT @VAR |
Ou parâmetros que têm seus valores alterados durante a execução de procedimentos armazenados (INPUT/OUTPUT):
using System; using System.Data; using System.Data.SqlClient; using System.Data.SqlTypes; using Microsoft.SqlServer.Server;
public partial class StoredProcedures { [SqlProcedure(Name = "USP_Primeiro")] public static void Primeiro (ref SqlString texto) { SqlContext.Pipe.Send(texto.ToString()); texto = new SqlString("VALOR 2"); } }; |
DECLARE @VAR NVARCHAR(4000) SET @VAR = N"VALOR 1" EXEC USP_Primeiro @VAR OUT PRINT @VAR |
Para as duas situações demonstradas anteriormente, o deploy se encarregará de criar estruturas adequadas para os procedimentos armazenados.
Com os procedimentos armazenados também é possível retornar valores inteiros, como detalhado abaixo.
using System; using System.Data; using System.Data.SqlClient; using System.Data.SqlTypes; using Microsoft.SqlServer.Server;
public partial class StoredProcedures { [SqlProcedure(Name = "USP_Primeiro")] public static SqlInt32 Primeiro() { return 333; } }; |
DECLARE @VAR INT EXEC @VAR = USP_Primeiro PRINT @VAR |
Concluindo este artigo, espero que tenham gostado desta primeira demonstração dos procedimentos armazenados, onde podemos identificar conceitos básicos de como o deploy se comporta com a customização do CLR, e a facilidade de customizar características dos procedimentos armazenados, sem a necessidade de envolvimento direto com o script de deploy.
No próximo artigo, estarei trabalhando as três principais formas de trabalhar com Stored Procedures desenvolvidas em CLR para retornar resultados de consultas ou simplesmente criar um resultado qualquer.
- Representando dados em XML no SQL ServerSQL Server
- Diferenças entre SEQUENCES x IDENTITY no Microsoft SQL Server 2012SQL
- Utilizando FILETABLE no SQL Server 2012SQL Server
- NHibernate com o Delphi Prism: Acessando um Banco de Dados SQL ServerVisual Studio
- Novidades no SQL Server Codinome DenaliSQL Server