diretor técnico - the club · do banco de dados passando ... join sys.query_store_plan as p ......
TRANSCRIPT
Caro leitor,
Preparamos para você este mês, uma revista cheia de novidades contendo os principais assuntos no mundo da
programação. Para iniciar nossa série de artigos, nosso colaborador Ricardo Barbosa Crivelli redigiu o assunto sobre a
tecnologia “AngularJS”, com o título “AngularJS - Usando servicos para compartilhar informacoes entre dois
controladores”. Ele nos ensina que os servicos são objetos denominados “singleton”, ou seja, que são instanciados somente
um por aplicação e são carregados somente quando forem necessários (método conhecido como lazy-load) e são
utilizados para manter a informação durante o ciclo de vida da aplicação. Já nosso colunista mensal Hamden Vogel
escreveu o artigo “Threads – Técnicas turbinadas e recursos interessantes de envio de e-mails via GMAIL”. Nesta primeira
parte ele implementa a classe “TProgressThread”, que seria a própria thread utilizada para medir o tempo de algum
processo. Artigo recomendável para o programador Delphi. Já nosso consultor Thiago Cavalheiro Montebugnoli abordou
um assunto relacionado ao Entity Framework no artigo “Entity Framework – Trabalhando com Transacoes”. Neste tutorial
ele cria um exemplo prático envolvendo entidades com mais de um modelo de dados utilizando a classe
“TransactionScope”. No outro artigo escrito por ele, chamado “Principais recursos do microsoft SQL Server 2016”, como o
próprio nome já diz, foi ressaltada as principais novidades deste poderoso Banco de Dados da Microsoft.
Desejo uma ótima leitura.
Um abraço!
Marcos César Silva
Diretor Técnico
Editorial
Principais recursos do Microsoft SQL Server
2016
No artigo deste mês irei explorar alguns recuros do lançamento da nova versão do Banco de Dados da Microsoft,
o Microsoft SQL Server 2016. Terei como base o E-Book gratuito escrito por Stacia Varga, Denny Cherry E Joseph D’
Antoni que está disponível no formato “pdf” no seguinte link: http://aka.ms/IntroSQLSvr2016PE_dsktp_pdf
É importante informá-los que o lançamento oficial foi no dia 07 de Abril de 2016 e sua versão “SQL Server
2016 Release Candidate 2” poderá ser baixada e instalada através do link: https://www.microsoft.com/pt-
br/evalcenter/evaluate-sql-server-2016
A ideia central deste artigo será de apenas apontar e explorar algumas novidades encontradas nesta nova versão
do banco de dados, sempre tendo como base o E-book supracitado, ou seja, não abordarei instalações, configurações,
entre outros recursos que explorarei com certeza em artigos futuros.
Segurança mais rígida O Microsoft SQL Server 2016 introduz diversos novos recursos relacionados à segurança de dados, sendo:
“Always Encrypted“, “Row-Level Security” e “Dinamic Data Masking”. Abaixo irei descrever todos estes recursos.
- Always Encrypted
Traduzindo para o português como “Sempre Crptografados”, é denominado como uma tecnologia de
criptografia do lado do cliente no qual os dados são automaticamente criptografados não apenas quando é escrito, mas
também quando ele é lido por um outro aplicativo. Ao contrário de criptografia de dados transparente, que criptografa
os dados no disco. Sua principal característica ao utilizar este tipo de controle, é que a aplicação transfere de forma
segura os dados criptografados no banco de dados que pode ser descriptografado depois apenas por um aplicativo
que tem acesso à chave de criptografia.
Exemplo:
CREATE TABLE dbo.EXEMPLO_CRIPTOGRAFIA
(
CODIGO INT IDENTITY(1,1) PRIMARY KEY
NOME VARCHAR(50),
DOCUMENTO VARCHAR(30),
DATA_NASCIMENTO DATE ENCRYPTED WITH
(
ENCRYPTION_TYPE = RANDOMIZED,
ALGORITHM = ‘AEAD_AES_256_CBC_HMAC_SHA_256’,
COLUMN_ENCRYPTION_KEY = MINHA_CHAVE
),
TIPO CHAR(10) ENCRYPTED WITH
(
ENCRYPTION_TYPE = DETERMINISTIC,
ALGORITHM = ‘AEAD_AES_256_CBC_HMAC_SHA_256’,
COLUMN_ENCRYPTION_KEY = MINHA_CHAVE
));
No exemplo acima, na criação do campo definimos o tipo, o algoritmo e a chave de criptografia. Utilizamos nos
campos “DATA_NASCIMENTO” e “TIPO” através do comando “ENCRIPTED WITH”.
- Row-Level Security
Este tipo de recurso permite configurar tabelas de tal forma que os usuários vejam apenas as linhas dentro da
tabela para a qual iremos conceder acesso. A “Row-Level Security” permitirá aos DBAs e profissionais da área de banco
de dados, realizar um controle de acesso aos dados que estão armazenados em determinadas tabelas, através do uso
de funções conhecidas como “Predicate”, limitando assim que uma possível coluna e seu respectivo valor seja
consultado.
Poderemos usar um “predicate” para filtrar silenciosamente as linhas que são acessíveis pelo usuário ao usar
“INSERT”, “UPDATE” ou “DELETE”. Além disso, poderemos também usá-los para o usuário de gravar dados através das
cláusulas: “AFTER INSERT”, “AFTER UPDATE”, “BEFORE UPDATE” e “BEFORE DELETE”.
Exemplo:
CREATE SCHEMA Seguranca
GO
CREATE FUNCTION Seguranca.acessoUsuarioPredicate(@UserName sysname)
RETURNS TABLE
WITH SCHEMABINDING
AS
RETURN SELECT 1 AS accessResult
WHERE @UserName = SUSER_SNAME()
GO
CREATE SECURITY POLICY Seguranca.acessoUsuarioPolicy
ADD FILTER PREDICATE Seguranca.acessoUsuarioPredicate(UserName) ON dbo.Tabela,
ADD BLOCK PREDICATE Seguranca.acessoUsuarioPredicate(UserName) ON dbo.Tabela
GO
No código acima foi criado uma função para adicionar e bloquear um usuário em uma
determinada tabela.
- Dynamic data masking
O Dynamic Data Masking, limita a exposição de dados confidenciais, os mascarando para usuários não-
privilegiados. O Mascaramento de dados dinâmico ajuda a evitar o acesso não autorizado a dados confidenciais,
permitindo aos clientes designar o quanto os dados confidenciais para revelar com impacto mínimo na camada de
aplicação. É uma característica de segurança que esconde os dados no conjunto de resultados de uma consulta sobre
campos de banco de dados designado, enquanto os dados no banco de dados não são alterados. Considerado de fácil
utilização com aplicativos existentes, desde que as regras de mascaramento sejam aplicadas nos resultados da consulta.
Muitos aplicativos podem mascarar dados confidenciais sem modificar consultas existentes.
Exemplo:
CREATE TABLE PESSOAS
(
ID int IDENTITY PRIMARY KEY,
NOME varchar(100) MASKED WITH (FUNCTION = 'partial(1,"XXXXXXX",0)') NULL,
SOBRENOME varchar(100) NOT NULL,
FONE varchar(12) MASKED WITH (FUNCTION = 'default()') NULL,
Email varchar(100) MASKED WITH (FUNCTION = 'email()') NULL
);
Ao criar os campos na tabela PESSOAS poderemos incorporar algumas máscaras existentes nesta nova versão
do SQL Server, como por exemplo: “PARTIAL”, “DEFAULT” e “EMAIL”, ambas precedidas do comando “MASKED”.
Melhorias no Motor do Banco de Dados
No Microsoft SQL Server 2016, poderemos encontrar uma funcionalidade melhorada em todo o motor (engine)
do banco de dados passando a gerir mais de um número muito maior de bases de dados SQL Server por meio de seu
banco de dados como um serviço (DBaaS). Neste item, vamos explorar algumas das novas funcionalidades dos
denominados “Query Store” e “Stretch Database”.
- Query Store
Esta funcionalidade irá nos auxiliar em muito em nossas longas jornadas de análise de planos de execução, a
“Query Store” vai dar a possibilidade de fazer a análise de uma plano de execução que possa estar apresentando
problemas de desempenho através de uma “indicação” ou “orientação” por parte do SQL Server, podendo escolher um
plano de execução para processar uma query. Podemos considerar esta característica como uma das maiores melhorias para o motor de banco do dados SQL
Server, desde a introdução de pontos de vista de gerenciamento dinâmico. Podemos corrigir diversos tipos de
problemas acarretando uma maior velocidade dos dados.
Exemplo: Habilitando o “Query Store” sem parâmetros.
ALTER DATABASE dbTheClub SET QUERY_STORE = ON;
Exemplo: Habilitando o “Query Store” com parâmetros.
ALTER DATABASE dbTheCLub
SET QUERY_STORE = ON
(
OPERATION_MODE = READ_WRITE,
CLEANUP_POLICY = (STALE_QUERY_THRESHOLD_DAYS = 5),
DATA_FLUSH_INTERVAL_SECONDS = 2000 ,
MAX_STORAGE_SIZE_MB = 10 ,
INTERVAL_LENGTH_MINUTES = 10
);
Exemplo de utilização do “Query Store”
SELECT TOP 10 rs.avg_duration,
qt.query_sql_text,
q.query_id,
qt.query_text_id,
p.plan_id,
GETUTCDATE() AS CurrentUTCTime,
rs.last_execution_time
FROM sys.query_store_query_text AS qt
JOIN sys.query_store_query AS q ON qt.query_text_id = q.query_text_id
JOIN sys.query_store_plan AS p ON q.query_id = p.query_id
JOIN sys.query_store_runtime_stats AS rs ON p.plan_id = rs.plan_id
WHERE rs.last_execution_time > DATEADD(hour, -1, GETUTCDATE())
ORDER BY rs.avg_duration DESC;
Na utilização de “Query Stores” teremos diversos tipos, como: query_store_query_text:
Texto da consulta digitado pelo usuário, incluindo espaços em branco, sugestões e comentários.
query_store_query: Informações de consulta e as suas estatísticas de execução.
query_store_plan: informações de plano de execução para consultas.
query_store_runtime_stats: estatísticas de tempo de execução para consultas.
- Stretch Database
Esta é uma funcionalidade bastante esperada principalmente para os usuários do Azure, através do “Strech
Database”, em português ficaria mais ou menos como “Base de Dados de Estiramento”, será possível armazenar porções
(partes ou fatias) de uma tabela no “Azure SQL Database”. Através deste recurso, temos a capacidade de armazenar
dados históricos contidos em uma tabela de forma segura e transparente diretamente na nuvem, ou melhor dizendo no
Microsoft Azure. A partir do momento que este recurso é habilitado, de forma silenciosa os dados considerados
históricos são migrados para um banco SQL Azure, tudo isso é feito pelo SQL Server sem exigir qualquer alteração de
código em sua query ou aplicação.
Importante: Para realizar este teste é necessário possuir uma conta Azure.
Exemplo para configurar a opção “REMOTE DATA ARCHIVE”:
EXEC sp_configure 'remote data archive', '1';
GO RECONFIGURE;
GO
Ou também podemos facilmente configurar via interface gráfica, clicando com o botão direito sobre a base de dados escolhendo “Tasks” e logo em seguida “Enable Database for Stretch...” Ver Imagem 01.
Figura 01: Configurando o “Database for Stretch...”
Conclusões
Procurei neste artigo discorrer um pouquinho das principais novidades desta novíssima versão do Banco de
Dados SQL
Server. De acordo com minhas pesquisas e leituras de artigos, a própria Microsoft está muito confiante neste novo
banco, o mesmo está promentendo ser ainda mais robusto para aplicações de pequeno, médio e grande porte.
Aproveito para indicar fortemente a leitura do e-book citado no ínicio do artigo para quem desejar obter
informações mais profundas sobre os assuntos abordados neste artigo, assim como outros inúmeros que poderão
encontrar lá com minuciosos detalhes.
Este é o primeiro de muitos artigos que a nossa equipe irá preparar para você.
Desejo a todos uma ótima leitura. Um abraço!
Referências
https://www.microsoft.com/pt-br/evalcenter/evaluate-sql-
server-2016 https://msdn.microsoft.com/en-
us/library/bb669076(v=vs.110).aspx
https://msdn.microsoft.com/en-us/library/mt130841.aspx
Sobre o Autor
Thiago Cavalheiro Montebugnoli, Adora aprender novas tecnologias. Formado pela Faculdade de Tecnologia de
Botucatu – SP (FATEC), já desenvolveu softwares utilizando a plataforma .NET, Delphi junto com Banco de Dados SQL Server e Firebird. Como experiências profissionais mais recentes, possui em seu currículo sua atuação no Centro de Processamento de Dados da Prefeitura
Municipal de Itaí-SP e atualmente compõe a equipe da Coordenadoria Tecnologia da Informação no IFSP – Instituto Federal do Estado de São Paulo em Avaré. Além disso, é colunista mensal da Revista The Club Megazine e é consultor Técnico do The Club. Possui as seguintes
certificações: MCP - Microsoft Certified Professional, MCTS - Microsoft Certified Technology Specialist, MCAD - Microsoft Certified Application Developer e MCSD - Microsoft Certified Solution Developer.
E-mail: [email protected]
AngularJS - Usando serviços para
compartilhar informações entre dois controladores
Introdução Até agora nós estávamos somente preocupados em como a view está amarrada com o $scope e como o controller
administra as informações. Para uma melhor performance os controllers são instanciados somente quando eles forem
necessários e são descartados quando eles não são.
O que são serviços? Os serviços são objetos singleton que são instanciados somente um por aplicação e são carregados somente quando
forem necessários (método conhecido como lazy-load). Eles são utilizados para manter a informação durante o ciclo de vida
da aplicação e transmiti-la de forma eficaz entre os controladores.
Código Inicial Vamos iniciar nosso artigo com uma página HTML básica que inclui dois arquivos Java Scripts, o com o framework e
o outro chamado de app.js com os códigos de nossa aplicação.
<!DOCTYPE html>
<html>
<head>
<title>The Club</title>
<script type="text/javascript"
src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.9/angular.min.js"></scrip
t>
<script type="text/javascript" src="app.js"></script>
</head>
<body>
<div ng-app="aplicacao">
<h1>Usando serviços para compartilhar informações entre dois
controladores</h1>
</div>
</body>
</html>
Neste exemplo nós estaremos criando um serviço para armazenar as mensagens e dois controles, um para renderizar
a lista das mensagens e outro para adicionar mais mensagens à lista.
Criando o módulo
Vamos criar um módulo chamado de mensagens.
/* Arquivo: app.js */
angular.module('aplicacao', []);
angular.module('aplicacao').factory('mensagens', function(){
});
O próximo passo é criar um objeto que vai carregar todas as dependências de nosso serviço e retorná-la sempre ao
final.
/* Arquivo: app.js */
angular.module('aplicacao', []);
angular.module('aplicacao').factory('mensagens', function(){
var mensagens = { };
return mensagens;
});
Feito isso vamos criar um objeto chamado de listaMensagens que vai conter inicialmente um vetor vazio. Esse vetor
vai servir para armazenar nossas mensagens.
angular.module('aplicacao', []);
angular.module('aplicacao').factory('mensagens', function(){
var mensagens = { };
mensagens.lista = [];
return mensagens;
});
A nossa próxima missão agora é criar um método que irá adicionar mensagens à nossa lista e para isso nós iremos
utilizar alguns métodos nativos, como o push que é utilizado para adicionar um elemento em um vetor e o método length que
retorna o tamanho do vetor, ou seja quantas mensagens estão armazenadas.
/* Arquivo: app.js */
angular.module('aplicacao', []);
angular.module('aplicacao').factory('mensagens', function(){
var mensagens = { };
mensagens.lista = [];
mensagens.adicionar = function(mensagem) {
mensagens.lista.push({
id: mensagens.lista.length,
texto: mensagem
});
}
return mensagens;
});
Criando os controladores Vamos criar os controladores que irão fazer uso de nosso módulo. Primeiro vamos criar o ListaController que irá
injetar nosso serviço mensagens e passar a lista para a view.
/* Arquivo: app.js */
angular.module('aplicacao', []);
[...]
angular.module('aplicacao').controller('ListaControlador', function (mensagens){
var self = this;
self.mensagens = mensagens.lista;
});
Agora vamos voltar ao nosso arquivo HTML e criar uma div que irá mostrar todas a nossa lista de mensagens.
<div ng-app="aplicacao">
<h1>Usando serviços para compartilhar informações entre dois
controladores</h1>
<div ng-controller="ListaControlador as listagem">
<p ng-repeat="mensagem in listagem.mensagens">
{{ mensagem.id }}: {{ mensagem.texto }}
</p>
</div>
</div>
A diretiva ng-repeat serve para iterar por nossa listagem dentro de nossa view e mostrar o conteúdo de cada
mensagem. Se você executar nosso código agora verá que a página continua em branco, já que nossa listagem está vazia.
Vamos criar um controlador chamado InsertControlador que irá injetar o nosso serviço mensagens. Ele irá conter também
um método chamado adicionaMensagem que usará a função adicionar criada em nosso serviço.
/* Arquivo: app.js */
angular.module('aplicacao', []);
[...]
angular.module('aplicacao').controller('InsertControlador', function
(mensagens){
var self = this;
self.adicionaMensagem = function(mensagem){
mensagens.adicionar(mensagem);
};
});
Vamos criar um formulário em nosso arquivo HTML para adicionarmos novas mensagens.
<div ng-controller="ListaControlador as listagem">
<p ng-repeat="mensagem in listagem.mensagens">
{{ mensagem.id }}: {{ mensagem.texto }}
</p>
</div>
<div ng-controller="InsertControlador as insert">
<form ng-submit="insert.adicionaMensagem(insert.mensagemPadrao)">
<input type="text" ng-model="insert.mensagemPadrao">
<button type="submit">Adicionar</button>
</form>
</div>
E para garantir que nós sempre tenhamos uma mensagem padrão para nossas mensagens declare a variável
mensagemPadrao em nosso controlador.
angular.module('aplicacao').controller('InsertControlador', function
(mensagens){
var self = this;
self.mensagemPadrao = 'The Club Megazine';
self.adicionaMensagem = function(mensagem){
mensagens.adicionar(mensagem);
self.mensagemPadrao = '';
};
});
Conclusão No artigo de hoje nós aprendemos como utilizar um serviço para trocar informações entre vários controladores. Este
foi um exemplo bem simples mas que mostra de forma bastante clara como devemos proceder em grandes aplicações. Um
abraço a todos e até a próxima!
Sobre o Autor
Ricardo Barbosa Crivelli, mais conhecido como Rico Crivelli, é formado como Bacharel em Sistemas de Informação e
Licenciado em Computação pela Universidade Estadual do Norte do Paraná, atualmente é Técnico em TI no Instituto Federal de São Paulo – Câmpus Avaré. Tem como especialidade a linguagem PHP e o framework Symfony, apesar de adorar trabalhar com front-end e
desenvolvimento mobile e possuir as certificações COBiT 4.1 Foundation e Delphi 2006 Developer.
E-mail: [email protected]
ADO. NET Entity Framework - Trabalhando
com Transações
No artigo deste mês farei o uso da classe “TransactionScope” presente no Namespace “System.Transaction” e
do ADO.NET Entity Framework, uma das principais tecnologias de persistência de dados englobada na plataforma .NET.
Para o exemplo utilizarei como ferramenta de desenvolvimento o Microsoft Visual Studio junto com a linguagem C#.
ADO.NET Entity Framework
Antes de começarmos a desenvolver o artigo achei necessário realizar uma abordagem rápida sobre o conceito
de desta tecnologia. O Entity Framework é uma camada de negócios existente para automatizar as atividades de banco
de dados relacionados para a sua aplicação. Esta estrutura suporta o desenvolvimento de aplicações orientadas a dados
permitindo a modelar entidades, relacionamentos e lógica de negócios.
Classe TransactionScope
Esta classe presente no .NET Framework desde a versão 2.0, fornece uma maneira simples de marcar um bloco
de código como participante de uma transação. Como foi dito anteriormente, esta classe tem origem do Namespace
“System.Transaction” e do Assembly “System.Transactions.dll” e possui os principais Construtores e Métodos.
Construtores (Ver Tabela 01)
Nome
Descrição
TransactionScope()
Inicializa uma nova instância da classe
TransactionScope.
TransactionScope(Transaction)
Inicializa uma nova instância da classe
“TransactionScope” e define a transação
especificada como a transação de ambiente, de
modo que o trabalho transacional dentro do
escopo utilize essa transação.
TransactionScope(Transaction, TimeSpan)
Inicializa uma nova instância da classe
“TransactionScope” com o valor de tempo limite
especificado, e define a transação especificada
como a transação de ambiente, de modo que o
trabalho transacional feito no escopo use essa
transação.
Metodos (Ver Tabela 02).
Nome
Descrição
Complete()
Indica que todas as operações no escopo sejam concluídas com êxito.
Dispose()
Termina o escopo da transação.
Equals(Object)
Verifica se o objeto especificado é igual ao objeto atual.
GetHashCode()
Serve como a função de “hash” para um tipo específico.
GetType()
Obtém o Type (tipo) da instância atual.
ToString()
Retorna uma string que representa o objeto atual.
Criando o exemplo
Antes de iniciarmos o exemplo gostaria de fazer uma consideração importante quando trabalhamos com o Entity
Framework. Para projetos pequenos, com no máximo 100 entidades inseridas no mesmo Modelo (Model) não há a
necessidade de realizar o controle de transações, pois todas as atualizações feitas através do Entity Framework já
acontecem em uma transação, ou seja, se ocorrer algum erro antes que o método “SaveChanges” esteja concluído, o
“RollBack” é garantido. Atribuímos este tipo de controle como transação implícita. Portanto, para este artigo iremos supor uma situação a qual iremos utilizar dois Modelos com algumas Entidades
para testes, sendo “Model1” e “Model2”. Fiquem a vontade para criar projetos do tipo Windows ou Web, no nosso caso
específico foi criado um projeto do tipo “Windows Forms” contendo apenas um botão no formulário para fins de testes.
Ver Imagem 01.
Figura 01: Criando um projeto de exemplo.
Na “Solution Explorer” clique com o botão direito sobre o projeto escolhendo “Add” / “New Item...”. Em “Visual
C# Items” em “Data” iremos adicionar um Modelo do tipo “ADO.NET Entity Data Model” com o Nome como “Model1”
e logo em seguida adicionar algumas Entidades para o nosso exemplo (Neste artigo não nos aprofundaremos nesta
etapa, pois a mesma já foi abordada em outros artigos). Seguiremos estes mesmos passos para adicionar o “Model2”.
Ver Imagem 02.
Figura 02: Adicionando dois Modelos de Dados (Model1 e Model2).
O primeiro passo ao trabalhar com Transações seria adicionar a referência “System.Transaction”. Para isto
clique com o botão direito sobre a “solution” escolhendo “Add/References” e navegue até a opção
“System.Transactions”. Ver Imagem 03.
Figura 03: Adicionando o Namespace System.Transaction.
O passo seguinte seria adicionar o Namespace ao projeto:
.
.
using System.Transactions;
.
.
No evento “Click” do botão iremos codificar o exemplo que fará a inserção de dados em duas tabelas e modelos
distintos, sendo na “Categories” e na “Territories”. Estas duas tabelas estão presentes na Base de Dados “NorthWind”.
Ver Listagem abaixo comentada.
private void btnExecutar_Click(object sender, EventArgs e)
{
Primeiramento foi declarado uma variável do tipo booleana “finalizado” para indicar se a transação foi realizada
com sucesso e logo em seguida instanciaremos o Modelo 1 e o Modelo 2.
bool finalizado = false;
Entities1 db1 = new Entities1();
Entities2 db2 = new Entities2();
Dentro de um “Try/Finally“ iremos instanciar a classe “TransactionScope”, responsável por envolver o bloco de
código em uma transação.
try
{
using(TransactionScope scope = new TransactionScope())
{
Nesta região iremos executar as tarefas pertinentes. No nosso caso irei inserir dados na tabela
Categories presente no “Model1”.
Categories categories = new Categories()
{
CategoryID = 1,
CategoryName = "The Club"
};
db1.Categories.Add(categories);
Já no “Model2” iremos inserir dados na tabela “Territories”.
Territories territories = new Territories()
{
TerritoryID = "98765",
TerritoryDescription = "Datasmart",
RegionID = 1
};
db2.Territories.Add(territories);
Até o momento todas as tarefas estão prestes a ser executadas no banco de Dados. Com o auxílio
do “Try/Catch” através do Método “SaveChanges” gravaremos as alterações realizadas no Contexto.
try
{
db1.SaveChanges();
db2.SaveChanges();
finalizado = true;
}
catch
{
finalizado = false;
}
A variável booleana “finalizado” indica se a transação foi realizada, sendo assim, faremos um “if”
para identificar se a mesma foi completada. O método “scope.Complete()” fará o “commit”.
if (finalizado)
{
scope.Complete();
}
}
Mostraremos uma mensagem informando ao usuário se a tarefa foi concluída ou não.
if (finalizado)
MessageBox.Show("Tarefa concluída com sucesso!");
else
MessageBox.Show("Ocorreu uma Exceção!");
}
Iremos liberar da memória os modelos usando o método “Dispose()”.
finally
{
db1.Dispose();
db2.Dispose();
}
}
O exemplo ficará idêntico ao da Imagem 04.
Figura 04: Exemplo em run-time.
Conclusões
Neste artigo procurei descrever o uso da classe “TransactionScope” junto com o “Entity
Framework”. O uso de transações é muito comum nos sistemas que necessitam “commitar” no banco de
dados múltiplas informações, devendo ser na totalidade completadas com sucesso. A classe
“TransactionScope” nos permite trabalhar exatamente desta maneira, utilizando vários modelos de dados
com um número grande de entidades.
Fica aí a dica, um abraço e até o mês que vem!
Referências
https://msdn.microsoft.com/pt-br/data/jj590134
http://www.entityframeworktutorial.net/what-is-entityframework.aspx
https://msdn.microsoft.com/pt-
br/library/system.transactions.transactionscope(v=vs.110).aspx
Sobre o Autor Thiago Cavalheiro Montebugnoli, Adora aprender novas tecnologias. Formado
pela Faculdade de Tecnologia de Botucatu – SP (FATEC), já desenvolveu softwares utilizando a plataforma .NET, Delphi junto com Banco de Dados SQL Server e Firebird. Como experiências profissionais mais
recentes, possui em seu currículo sua atuação no Centro de Processamento de Dados da Prefeitura Municipal de Itaí-SP e atualmente compõe a equipe da Coordenadoria Tecnologia da Informação no IFSP
– Instituto Federal do Estado de São Paulo em Avaré. Além disso, é colunista mensal da Revista The Club Megazine e é consultor Técnico do The Club. Possui as seguintes certificações: MCP - Microsoft Certified Professional, MCTS - Microsoft Certified Technology Specialist, MCAD - Microsoft Certified Application
Developer e MCSD - Microsoft Certified Solution Developer.
E-mail: [email protected]
Threads – técnicas turbinadas e recursos interessantes de envio de emails via GMail –
parte I
Olá leitores, vamos neste artigo explicar coisas que nem sempre são utilizadas em aplicações do mundo real, como recursos thread-safe,
thread para acompanhamento de tempo, gerenciamento de threads via enfileiramento, thread para envio de email via conta GMail e gerenciamento
de recursos críticos compartilhados via classes TCriticalSection e TMultiReadExclusiveWriteSynchronizer.
Para que se importar com estas funcionalidades? Aplicações que utilizam recursos para gravação, como escrever dados em um objeto do tipo
TListBox ou TClientDataSet, arquivos do tipo TextFile ou envio de dados a banco de dados – todos eles podem operar bem no mesmo processo que a
sua aplicação – sua aplicação tem apenas uma thread, que é o seu form principal – e até aí então tudo bem. Porém imagine agora uma aplicação
multi-thread cujo cenário utilize concorrentemente estes recursos – e como agora são entre threads estes mesmos recursos passam a ser recursos
críticos pelo fatos de serem compartilhados entre si – e por isso sua aplicação agora precisa tratar o controle de acesso simultâneo a estes recursos,
senão sua aplicação poderá entrar em deadlock – e isso não é uma maneira legal de resolver os problemas – precisamos de uma solução satisfatória
que previna o acesso a mais de um escritor enquanto se já um outro escritor chegar primeiro. E portanto chegamos as classes citadas acima
TCriticalSection e TMultiReadExclusiveWriteSynchronizer, mas a segunda mencionada é melhor para o nosso cenário pelo fato da mesma não ficar
enfileirando as demais threads – apenas bloqueando o acesso de escrita enquanto já tiver sido iniciado por outra thread (múltipla leitura, escrita
exclusiva). Vamos iniciar o nosso artigo implementando a classe TProgressThread, que é a nossa thread utilizada para medir o tempo ilustrativamente de
algum processo – a classe TTimer não funcionada para ambientes multi-thread – precisamos “marcar” o tempo de outra forma – ou seja utilizando a função WaitForSingleObject da API Kernel32 do Windows para fatiar o tempo em ciclos pré-definidos, permanecendo em um
loop desta thread e sincronizando com o evento do sistema de tempos em tempos, algo como (onde 1000 significa 1000 milésimos de segundo =>
1 segundo => de 1 em 1 segundo a função executa =>):
“ while not Terminated do
if WaitForSingleObject(FTickEvent, 1000) = WAIT_TIMEOUT then
Synchronize(Form1.ShowProgress);”
Utilizamos também a função (também o Windows) CreateEvent para criar um evento do sistema com uma variável do tipo THandle (FTickEvent) para
a função WaitForSingleObject.
Desenhando nossa TProgressThread para medir o tempo das rotinas
Esta classe a ser explicada aqui é interessante. Permite mostrar o andamento de um trabalho, via multi-thread, e utilizados alguns componentes
da VCL, como objetos de TImage, TPanel (parent do TImage) e de TImageList. Este último contém as partes das figuras necessárias para a ilustração no
sentido horário, como pode ser visto abaixo:
Figuras de 1 a 5 – exemplo de implementação real via multi-thread da classe TProgressThread.
type
TProgressThread = class(TThread)
private
FTickEvent: THandle;
procedure FinishThreadExecution;
protected
procedure Execute; override;
public
constructor Create(CreateSuspended: Boolean);
destructor Destroy; override;
end;
{ TProgressThread }
constructor TProgressThread.Create(CreateSuspended: Boolean);
begin
inherited;
FreeOnTerminate := True;
FTickEvent := CreateEvent(nil, True, False, nil);
Synchronize(Form1.ShowPanelProgress);
end;
destructor TProgressThread.Destroy;
begin
CloseHandle(FTickEvent);
inherited;
end;
procedure TProgressThread.Execute;
begin
MyCS.Enter;
try
while not Terminated do
if WaitForSingleObject(FTickEvent, 100) = WAIT_TIMEOUT then
Synchronize(Form1.ShowProgress);
finally
MyCS.Leave;
end;
end;
procedure TProgressThread.FinishThreadExecution;
begin
Synchronize(Form1.HidePanelProgress);
Form1.ProgressImagePanel.Visible := False;
Terminate;
SetEvent(FTickEvent);
end;
Com isso vimos acima um trecho do código-fonte responsável por essa implementação. Podemos associar esta classe, que é uma thread, para
ser chamada em outras threads, e assim sendo a ilustração de progresso se mostrará com perfeição entre as execuções dos processos, até que seja
encerrado explicitamente pelo método FinishThreadExecution – esse método também poderá ser sincronizado
(Synchronize(Self.FinishThreadExecution)) para que a animação de progresso seja fechada com sucesso. Segue abaixo as funções de sincronização
chamadas pela classe TProgressThread, que deverão ser incluídas em algum formulário (recomendável o formulário em que está sendo chamado a
thread):
procedure TForm1.FormCreate(Sender: TObject);
begin
ProgressImagePanel.DoubleBuffered := True;
ProgressImages.GetBitmap(0, ProgressImage.Picture.Bitmap);
end;
procedure TForm1.ShowProgress;
begin
ProgressImages.Tag := (ProgressImages.Tag + 1) mod ProgressImages.Count;
ProgressImages.GetBitmap(ProgressImages.Tag, ProgressImage.Picture.Bitmap);
ProgressImage.Refresh;
end;
procedure TForm1.HidePanelProgress;
begin
ProgressImagePanel.Visible := False;
end;
procedure TForm1.ShowPanelProgress;
begin
ProgressImagePanel.Visible := True;
end;
Assim sendo, esta thread será chamada em outras threads, e quando o processamento dela estiver pronta chamaremos o método
FinishThreadExecution dela, como já dito anteriormente. Não tem coisa melhor que mostrar na prática em um exemplo real, e por isso vamos agora ilustrar uma maneira realmente interessante,
que é o envio de emails a partir de uma lista, utilizando então esta thread. Vamos discorrer sobre outra thread, a TSendMailThread. Enviando Emails
Vamos abordar daqui pra frente o processo de envio de emails pelo Delphi, de uma forma prática e independente de aplicativos como
Outlook, etc; será uma forma feita exclusivamente por componentes de terceiros do Delphi. Explicações Iniciais
Não vamos de cara mostrar os fontes de como mandar email sem antes configurar o ambiente, porque não é só isso; além de instalar certos
componentes tem que distribuir Dll´s em diretórios do Windows também. Acompanhando tudo desde o início é a melhor forma para aprendizado, e
até para fazer um “deploy” do produto é importante (você pode criar uma rotina automatizada para copiar as dll´s necessárias do Indy para o diretório
do Windows, por exemplo). Então vamos configurar uma estrutura para que possa enviar emails a partir de uma conta do GMail, chamada pelo Delphi,
em um ambiente multi-thread. A thread TSendMailThread terá esse objetivo.
Instalação do ambiente
As configurações se referem ao compilador Delphi 7. É altamente recomendável também migrar a versão dos componentes Indy. A versão
utilizada foi a 10. Site oficial do Indy: http://www.indyproject.org/Sockets/Download/svn.EN.aspx
Então vamos abordar as principais características relevantes:
1. Baixar pelo SVN (https://svn.atozed.com:444/svn/Indy10) userId “Indy-Public-RO” e sem senha todo o fonte do Indy10 para seu
computador;
2. Instalar os pacotes necessários necessariamente nesta mesma ordem informada abaixo (favor referir-se a documentação ou proceder
conforme abaixo);
Compilar (e sem instalar, apenas compilar!) IndySystem70.dpk (subdiretório Lib\System);
Compilar (e sem instalar, apenas compilar!) IndyCore70.dpk (subdiretório Lib\Core);
Compilar (e sem instalar, apenas compilar!) IndyProtocols70.dpk (subdiretório Lib\Protocols);
3. Agora instalar os pacotes dclIndyCoreX7.bpl e dclIndyProtocolsX7.bpl necessariamente nesta ordem; qualquer problema consultar o site
http://www.indyproject.org/Sockets/Docs/Indy10Installation.EN.aspx;
4. Mapear no Delphi em Library Path (Tools/Environment Options) para que sejam localizados os fontes do Indy, na ordem abaixo:
caminhodaInstalação\trunk\Lib\System;
caminhodaInstalação\trunk\Lib\Core;
caminhodaInstalação\trunk\Lib\Protocols;
5. Distribuir as dll´s libeay32.dll e a ssleay32.dll para “c:\windows\SysWOW64” (64 Bits)
ou “c:\windows\System32” (32 Bits). Provavelmente será a de 64. Elas podem ser baixadas no link (fiz upload pro meu FTP) em
http://hvogel.com.br/temp/dlls.rar;
1. Obviamente, possuir uma conta no GMail; é como se o próprio GMail enviasse os emails; se olhar nos itens enviados percebe-se que os emails
estão lá. Na verdade nosso programa “simula” esta operação, pois na verdade essa operação é endereçada para os serviços do servidor smtp
(Simple Mail Transfer Protocol – protocolo padrão para envio de e-mails através da Internet) do GMail (smtp.gmail.com);
2. Na conta do GMail acessar o ícone de configurações ( ) localizado no canto superior direito, e selecione em
“Configurações”. Então selecione a tab “Encaminhamento e POP/IMAP” e selecione “Ativar IMAP” na seção “Acesso ao IMAP”;
3. Acessar o recurso do GMail de habilitar aplicações com menos segurança para acessar ele. Acesse o link
“https://www.google.com/settings/security/lesssecureapps” e clique em “turn on” para manter ele ativado.
Demais configurações nossa aplicação proverá de dentro do fonte, para que seja instanciada as classes relevantes do Indy para o seu correto
acesso em tempo de execução (como por exemplo as classes TIdSMTP, TIdMessage e TIdSSLIOHandlerSocketOpenSSL) e demais configurações
relevantes, como número da porta do servidor (465) e é claro, o usuário e senha corretamente especificados (o usuário é no formato
usuá[email protected]). Podemos especificar que passaremos um texto no formato HTML que será felizmente renderizado neste formato – uma
observação no que diz respeito a imagens – o GMail bloqueia imagens recebidas – a única exceção são imagens já contidas em algum servidor. Não
adianta imagens linkadas de dentro do seu computador ou convertidas como codificação formato Base64 – vai bloquear do mesmo jeito. A solução
como dita anteriormente é referenciar as imagens a algum site que já contenha essas imagens já armazenadas (exemplo:
http://hvogel.com.br/img/lupa.png). A última observação é a utilização do formato MIME (MultiPurpose Internet Mail Extensions) que define o
formato das mensagens de correio eletrônico utilizando o protocolo SMTP já mencionado anteriormente.
Conclusão
Vimos a configuração básica e essencial para que seja construída em cima disso uma aplicação funcional multi-thread cujo arcabouço foi
definido no escopo deste artigo. A próxima continuação vai discorrer sobre as classes thread mencionadas aqui juntamente com a continuação do
tema do envio de emais via conta do GMail. Demos muito foco sobre a correta configuração desde a instalação dos arquivos e dll´s e a compilação
destes artefatos nos locais corretos e adequados para uma correta execução desta rotina interessante de envio de emails. Vale ressaltar que é muito
difícil, árduo e cansativo encontrar tudo isso na internet; são encontradas informações muito mal explicadas e apenas em parte, bem como informações
obsoletas e incompletas – foi o que levou a discorrer sobre este tema, bem como a necessidade própria de escrever esta funcionalidade para um
amigo em particular que me fez também interessar sobre esta função de envio de emails.
Continuaremos em detalhes mais minuciosos, passo a passo, para um eficiente aplicativo profissional multi-thread que enviará emails
coletados em um banco de dados nosso. Não percam, será muito interessante e a ideia já antepasso a informação que é inovadora. Os fontes também
serão entregues juntos. Não percam a próxima edição e enquanto isso instalem de forma cuidadosa, todo o ambiente descrito acima nas informações
repassadas.
Até a próxima.
Sobre o Autor
Hamden Vogel Consultor TheClub
E-mail: [email protected]