Entity Framework - Usando Transações
Neste artigo vamos mostrar como realizar transações usando o ADO .NET Entity Framework, e, como é um artigo introdutório ao assunto irei trabalhar com um cenário simplificado focando somente em mostrar como podemos realizar transações.
Conheça a regra de ouro para atualizações de múltiplas tabelas em um processo ? Se você não conhece vai conhecer agora, a regra diz o seguinte : "Todas as atualizações realizadas em um único processo que afetam mais de uma tabela deverão estar sobre o controle de uma transação"
O Entity Framework(EF) suporta transações e isto significa que as atividades realizadas dentro de um contexto de objeto, como a execução de consultas e a persistências das alterações , podem ser isoladas pela execução da operação no interior de uma transação. A transações são usadas no EF para realizar as seguintes ações:
Quando tratamos com transações no Entity Framework devemos levar em consideração os seguintes fatos:
No exemplo deste artigo eu vou usar uma outra forma de gerenciar uma transação usando a classe DBTransaction que é a classe base para uma transação.
Eu poderia usar o Banco de dados Northwind.mdf e suas tabelas mas para tornar o artigo mais simples eu vou criar apenas duas tabelas no banco de dados Northwind.mdf usando o SQL Server Management Studio : Categorias e Produtos com a estrutura mostrada nas figuras abaixo:
Tabela Categorias:
Tabela Produtos:
Agora vamos criar um novo projeto do tipo Windows Forms Application no Visual Basic 2010 Express Edition com o nome EF_Transacao1;
Agora vamos criar um Entity Data Model e realizar o mapeamento ORM para as tabelas do nosso banco de dados gerando o modelo de entidades que usaremos no projeto;
No menu Project selecione Add New Item e selecione ADO .NET Entity Data Model informando o nome Macoratti.edmx (ou outro a sua escolha) e clique em Add;
Na próxima janela do assistente selecione a opção Generate from database e clique em Next>;
A seguir selecione a conexão com o banco de dados que foi criado , no meu caso Northwind.mdf, e altere o nome da string de conexão para MacorattiEntities clique em Next>;
Na janela seguinte selecione as tabelas Categorias e Produtos, aceite o nome do namespace do Model e clique em Finish;
Ao final teremos o modelo de entidades gerado e as entidades Categoria e Produto mapeadas para as tabelas Categorias e Produtos bem como o contexto contendo os métodos que iremos usar para gerenciar o modelo de entidades e realizar a persistência dos dados;
Observe que no projeto temos o arquivo App.Config a string de conexão salva conforme abaixo:
<?xml version="1.0" encoding="utf-8"?> <configuration> <startup> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0,Profile=Client" /> </startup> <connectionStrings> <add name="MacorattiEntities" connectionString="metadata=res://*/Macoratti.csdl|res://*/Macoratti.ssdl|res://*/Macoratti.msl;provider= System.Data.SqlClient;provider connection string="Data Source=.\SQLEXPRESS;AttachDbFilename=C:\dados\Northwind.MDF; Integrated Security=True;Connect Timeout=30;User Instance=True;MultipleActiveResultSets=True"" providerName="System.Data.EntityClient" /> </connectionStrings> </configuration> |
Vamos criar uma pasta no projeto chamada BO (Business Objects) no projeto e criar nesta pasta a nossa classe de negócio chamada BOCategoriaProduto;
Para criar a pasta selecione a opção New Folder no menu Project e informe o nome da pasta: BO
Para criar as classe clique com o botão direito do mouse sobre a pasta e selecione Add -> Class , e , a seguir selecione o template Class e informe o nome da classe: BOCategoriaProduto
A classe BOCategoriaProduto definida no arquivo BOCategoriaProduto.vb deverá possuir o seguinte código:
Imports System.Data.Common Imports System.Data.EntityClient Public Class BOCategoriaProduto Public Shared Function CriarCategoriaProduto(ByVal categoriaToAdd As Categoria, ByVal produtoToAdd As Produto) As Boolean 'define uma escopo da transação Dim Transaction As DbTransaction = Nothing 'usa a conexão definida no arquivo App.config Using DatabaseConnection As New EntityConnection("name=MacorattiEntities") Try 'verifica o estado da conexão: se estiver fechada então abre If DatabaseConnection.State = ConnectionState.Closed Then DatabaseConnection.Open() End If 'cria uma instãncia do Contexto gerado no Entity Data Model Dim contextoAtual = New MacorattiEntities(DatabaseConnection) Transaction = contextoAtual.Connection.BeginTransaction() 'Incluir a Categoria" contextoAtual.AddToCategorias(categoriaToAdd) contextoAtual.SaveChanges() 'Pega o CategoriaID da nova categoria incluida" Dim CategoriaId As Integer = categoriaToAdd.categoriaid 'retorna o CategoriaID da nova Categoria adicionada. If CategoriaId < 1 Then Throw New ApplicationException("Não foi possível obter a identificação da categoria a nova categoria incluída.") End If 'Insere detalhes 'Fornece uma referência a um objeto que é uma instância de um tipo da entidade produtoToAdd.CategoriaReference.EntityKey = New EntityKey("MacorattiEntities.Categorias", "categoriaid", CategoriaId) contextoAtual.AddToProdutos(produtoToAdd) contextoAtual.SaveChanges() 'Confirma a transação Transaction.Commit() Return True Catch 'desfaz a transação Transaction.Rollback() Throw Finally If DatabaseConnection IsNot Nothing Then If DatabaseConnection.State = ConnectionState.Open Then DatabaseConnection.Close() End If End If End Try End Using End Function End Class |
Para testar vamos incluir no formulário form1.vb dois controles TextBox e um Button conforme o leiaute abaixo:
Inclua a seguir o código abaixo no evento Click do controle Button:
Private Sub btnTransacao_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnTransacao.Click Dim categoria As String Dim produto As String If txtCategoria.Text = String.Empty Then categoria = Nothing Else categoria = txtCategoria.Text End If If txtProduto.Text = String.Empty Then produto = Nothing Else produto = txtProduto.Text End If Try 'Popula a Categoria Dim ObjCategoria As New Categoria() ObjCategoria.categorianome = categoria 'Popula o Produto Dim ObjProduto As New Produto() ObjProduto.produtonome = produto 'Inclui a Categoria e o Produto If BOCategoriaProduto.CriarCategoriaProduto(ObjCategoria, ObjProduto) Then MsgBox("Categoria e Produto incluidos com sucesso...") End If Catch exp As Exception MsgBox("Erro ao incluir Produto e Categoria :: " + exp.Message) End Try End Sub |
Para testar o projeto iremos definir uma Categoria e um Produto e tentar incluir ambos usando uma transação de forma que se a inclusão da categoria falhar a transação não deverá ser confirmada (comitada) de forma que o produto também não será incluído.
Executando o projeto iremos obter a formulário form1.vb apresentando a categoria e o produto a incluir;
Ao clicar no botão de comando iremos obter uma mensagem de sucesso indicando que ambos foram incluídos na base de dados.
Verificando as tabelas confirmamos que tanto a categoria como o produto foram incluídas na mesma transação conforme a figura abaixo:
Confirmamos a inclusão da categoria Informática e do produto Mouse na respectiva categoria; |
Dessa forma mostrei um dos caminhos possíveis de trabalhar com transações com o Entity Framework.
Aguarde em breve novos artigos sobre o tema.
Eu sei é apenas Entity Framework mas eu gosto...
Referências:
José Carlos Macoratti