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=&quot;Data Source=.\SQLEXPRESS;AttachDbFilename=C:\dados\Northwind.MDF;
Integrated Security=True;Connect Timeout=30;User Instance=True;MultipleActiveResultSets=True&quot;" 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