André Alves de Lima

Talking about Software Development and more…

Utilizando o Oracle com C# e VB.NET

De acordo com o ranking do site DB-Engines, o Oracle é atualmente o banco de dados relacional mais utilizado no mundo. Quando eu comecei a trabalhar na Savcor em 2008, eu lembro que a instalação e configuração do Oracle, bem como a instalação do provider .NET, eram desafiadores. Eram muitos detalhes que tínhamos que prestar atenção para que tudo funcionasse corretamente. E o PL/SQL Developer? Como eu tinha ódio daquela ferramenta.

Desde 2008 eu venho trabalhando somente com SQL Server nas aplicações que eu tenho desenvolvido. Mas, como sempre é bom ficar por dentro das mais diversas tecnologias (principalmente quando estamos falando do banco de dados relacional mais utilizado do mundo), eu resolvi dar uma olhada no processo da instalação, configuração, gerenciamento e utilização do Oracle com C# e VB.NET. Veja só o que eu aprendi.

Instalando o Oracle Database Express

Como eu não trabalho normalmente com o Oracle, eu não entendo muito do modelo de licenciamento dele, ou seja, não sei quanto custa a licença da versão Standard ou Enterprise e não consegui encontrar a informação no site (aliás, que site complicado, não?). Inclusive, se alguém tiver mais experiência nessa área, fala para gente como é que funciona lá na caixa de comentários (ou me manda um e-mail com os detalhes aí eu coloco as informações no artigo dando crédito para você).

Dito isso, ao invés de me aventurar com alguma edição mais profissional do Oracle, eu decidi utilizar a edição Oracle Database Express, que é gratuita. No site da Oracle, procure pelo item “Oracle Database 11g Express“:

Aceite os termos de licença e baixe a versão que fizer mais sentido para você:

A instalação é muito simples, no estilo “next, next, finish” das instalações de aplicativos Windows. Basicamente a única coisa que você precisa escolher é a senha do usuário administrador.

Uma vez que você for apresentado com esta tela, a instalação foi concluída com sucesso:

Logo de cara, vi que a instalação criou um ícone no desktop, além de algumas entradas no menu iniciar:

Porém, ao tentar executar a opção “Get Started with Oracle Database“, recebi essa bela mensagem de erro:

Que bela experiência pós-instalação, hein Oracle? Enfim, pesquisei rapidamente sobre esse erro e encontrei esta thread no StackOverflow. Seguindo as instruções, chamei a URL “http://localhost:8080/apex/f?p=4950” no browser e, aí sim, consegui abrir as opções de configuração do Oracle:

Muito bem, com isso eu tive a certeza que o banco de dados foi realmente instalado com sucesso e que ele estava rodando.

Limitações da edição Express

Antes de continuarmos com o artigo, vamos dar uma olhada nas limitações do Oracle Database Express. Como toda versão gratuita, é natural esperarmos que ela seja limitada de alguma forma.

Como podemos observar na Wikipedia, a primeira versão do Oracle Database Express (10g, lançada em 2005) tinha as seguintes limitações:

– Utiliza somente um CPU do computador onde estiver instalado
– Somente um máximo de 1GB de memória RAM é utilizado pelo processo
– Banco de dados limitado a 4GB de armazenamento

Depois de um tempo, a partir da versão 11g (lançada em 2011), a Oracle decidiu aumentar o limite de armazenamento do banco de dados para 11GB. Essas limitações são quase idênticas às limitações do SQL Server Express (com a única diferença que o SQL Server Express tem um limite de 10GB por database, ao invés de 11GB do Oracle). É claro que você não vai colocar o ERP da sua empresa rodando em uma versão gratuita do Oracle ou SQL Server (pelo menos não deveria), mas, mesmo com essas limitações, dá para rodar uns sistemas bem consideráveis com essa edição gratuita.

Ferramentas de administração

OK. Até agora nós já conseguimos instalar o banco de dados e entendemos as limitações da edição Express. E agora, cadê o correspondente ao “SQL Server Management Studio” do Oracle? Como eu falei anteriormente, um dos meus maiores pesadelos quando trabalhei com Oracle no passado foi a ferramenta PL/SQL Developer que, comparada ao SQL Server Management Studio, não chega nem perto (na minha opinião), além de ser paga. Então, resolvi pesquisar sobre ferramentas gratuitas de administração do Oracle e encontrei esta outra thread no StackOverflow, onde acabei descobrindo que as principais ferramentas são o Oracle SQL Developer (da própria Oracle) e o Database.NET.

Eu comecei dando uma olhada no Oracle SQL Developer e ele acabou servindo para o que eu estava precisando neste artigo (administração básica do banco de dados, criação de usuários, tabelas, etc). Dessa forma, vou utilizá-lo nesse artigo para criarmos o banco de dados. Se você estiver mais familiarizado com o Dababase.NET ou alguma outra ferramenta de administração, fique à vontade para utilizar a ferramenta que você preferir.

Edit: O Marcelo Ramos indicou nos comentários a ferramenta de administração TOAD for Oracle. Eu não conhecia essa ferramenta, mas, parece ser bem bacana. Vale a pena dar uma conferida.

Criando uma tabela com o Oracle SQL Developer

O Oracle SQL Developer pode ser baixado no próprio site da Oracle:

Atente-se para baixar a versão que já vem com o JDK, senão você precisará ter o JDK instalado no seu computador:

Uma coisa interessante é que nós não precisamos, de fato, instalar o Oracle SQL Developer. Ele é um arquivo zip que você pode descompactar no seu computador e executar o arquivo “sqldeveloper.exe” para abrir a aplicação.

Com a aplicação aberta, tentei criar uma nova conexão utilizando o usuário admin (SYS), mas, recebi um erro falando que só consigo conectar como “SYS” utilizando a role SYSDBA ou SYSOPER. Muito bem, o problema é que eu deixei a role “Default” na hora de conectar:

Basta mudar o valor no ComboBox “Role” para SYSDBA que a conexão funcionará normalmente (não sei porque o banco de dados já vem com umas 500 tabelas já criadas, mas, tudo bem – OK, acabei aprendendo depois que essas tabelas apareceram porque eu loguei com o usuário de sistema):

Para analisarmos o funcionamento do Oracle em uma aplicação de exemplo, vamos seguir a mesma estratégia que eu utilizei no artigo sobre SQLite e vamos criar uma nova tabela extremamente simples, chamada “Cliente“, contendo somente uma coluna “Id” (chave primária, auto-incremento) e “Nome“:

Onde é que nós definimos uma coluna como auto-incremento no Oracle? Pois bem. Se você não sabe, o Oracle não tem uma coluna do tipo “auto-incremento” como o SQL Server ou MySQL. No Oracle isso é feito através de uma funcionalidade chamada “sequence” em conjunto com uma trigger de inserção de registros na tabela. Felizmente, com o Oracle SQL Developer, nós não temos que criar tudo isso manualmente. Ao ativarmos o modo avançado, nós conseguimos encontrar a opção “Identity Column” na tela de criação de tabelas. Aí é só alterar o tipo para “Column Sequence” e a coluna terá o comportamento de auto-incremento:

Será que se a gente clicar em “OK” a criação dessa simples tabela vai funcionar? É claro que não! Para não perder o costume, receberemos esse belo erro:

Como você pode perceber pela mensagem de erro, o Oracle não permite a criação de triggers em objetos que são do usuário de sistema. E, como eu mencionei anteriormente, a funcionalidade de auto-incremento no Oracle é implementada através de uma “sequence” em conjunto com uma trigger. E agora? O que fazemos? Pesquisando sobre esse erro, eu descobri nessa thread do StackOverflow que temos que criar um outro usuário para podermos fazer a criação dos objetos no nosso banco de dados (o que faz sentido – a criação de objetos no banco de dados com o usuário de sistema não é recomendada em nenhuma ferramenta de banco de dados).

Primeiramente, vamos deletar a tabela “CLIENTE” que foi criada pela ferramenta. Pois é. Mesmo tendo recebido o erro da trigger, a tabela foi criada:

Em seguida, criamos um novo usuário, clicando com o botão direito em “Other users” e escolhendo a opção “Create User“:

Eu dei o nome de “dbuser” para o novo usuário e adicionei todas as permissões para ele:

Obviamente, em um servidor de verdade você deveria criar o usuário somente com as permissões que ele deveria ter, mas, para fins didáticos neste artigo, eu configurei permissão total para o usuário.

Uma vez criado o usuário, vamos alterar a conexão para que ela não utilize mais o usuário de sistema, mas sim, esse usuário que acabamos de criar. Para isso, nós precisamos primeiramente desconectar do servidor:

Depois, nas propriedades da conexão, nós alteramos o usuário e senha:

Pronto! Agora se você seguir os mesmos passos que seguimos anteriormente para criarmos a tabela de Cliente, tudo vai funcionar sem nenhum erro:

Instalando o provider e suporte ao Visual Studio do Oracle

Ufa! Agora que já conseguimos finalmente criar a nossa singela tabela de Clientes, vamos partir para o desenvolvimento. Porém, antes disso, temos que instalar o provider e as ferramentas de suporte ao Visual Studio. Essas ferramentas podem ser baixadas diretamente no site da Oracle:

Eu recomendo a opção “ODAC + Developer Tools“. Essa é a opção mais completa, que instalará também o provider do Oracle para .NET, além do suporte ao Oracle no Visual Studio:

A instalação é bem tranquila. A única etapa que você tem que prestar atenção é o “DB Connection Configuration“. Nessa etapa o instalador perguntará os dados do seu servidor para que ele possa criar automaticamente as entradas no arquivo “tnsnames.ora” (se você não sabe, uma das formas para se conectar a um banco Oracle é utilizar o nome da entrada nesse arquivo na string de conexão – veremos mais informações sobre isso nas próximas seções deste artigo):

Acessando o Oracle com ADO.NET puro

Uma vez instalado o provider e ferramentas de suporte ao Visual Studio do Oracle, podemos partir para o desenvolvimento do nosso código de exemplo. Vamos ver como fazemos para implementarmos um CRUD (create, read, update, delete) bem básico em cima da tabela de Clientes?

Para simplificar as coisas, vou criar um novo projeto do tipo “Console Application“. Com o projeto criado, vamos adicionar a referência para a dll que implementa o suporte ao ADO.NET para o Oracle, que está localizada dentro da categoria “Extensions“:

Adicionada essa referência, nós já conseguimos trabalhar com as famosas classes do ADO.NET para o Oracle (OracleConnection, OracleCommand, OracleDataAdapter, etc). Todas essas classes estão localizadas no namespace “Oracle.DataAccess.Client“. A primeira coisa que vamos fazer é instanciar uma conexão e abri-la:

            // C#
            using (var conn = new Oracle.DataAccess.Client.OracleConnection("Data Source=dbserver;User Id=dbuser;Password=dbuser;"))
            {
                conn.Open();
            }
        ' VB.NET
        Using Conn As New Oracle.DataAccess.Client.OracleConnection("Data Source=dbserver;User Id=dbuser;Password=dbuser;")
            Conn.Open()
        End Using

Note que eu utilizei as informações criadas no arquivo “tnsnames.ora“, ou seja, o nome da entrada TNS escolhida durante a instalação das ferramentas de suporte ao Visual Studio do Oracle. Até uns tempos atrás, essa era a única opção para nos conectarmos a um banco de dados Oracle. Porém, felizmente, a partir de uma certa versão do Oracle (que eu não sei ao certo), nós podemos especificar todas as informações do banco de dados diretamente na string de conexão, sem termos que nos preocupar com o arquivo “tnsnames.ora“. Você encontra mais informações sobre essas strings de conexão aqui e aqui. No meu caso, a string de conexão sem utilizar o TNS ficou assim:

            // C#
            using (var conn = new Oracle.DataAccess.Client.OracleConnection("Data Source=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=localhost)(PORT=1521))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=XE)));User ID=dbuser;Password=dbuser;"))
            {
                conn.Open();
            }
        ' VB.NET
        Using Conn As New Oracle.DataAccess.Client.OracleConnection("Data Source=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=localhost)(PORT=1521))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=XE)));User ID=dbuser;Password=dbuser;")
            Conn.Open()
        End Using

Agora que já temos a nossa conexão instanciada e aberta, podemos começar a criar comandos para efetuarmos as nossas operações CRUD. A primeira operação que faremos é a exclusão de todos os dados da tabela de Clientes:

                // C#
                using (var comm = new Oracle.DataAccess.Client.OracleCommand())
                {
                    comm.Connection = conn;
                    comm.CommandText = "DELETE FROM Cliente";
                    comm.ExecuteNonQuery();
                }
            ' VB.NET
            Using Comm As New Oracle.DataAccess.Client.OracleCommand()
                Comm.Connection = Conn
                Comm.CommandText = "DELETE FROM Cliente"
                Comm.ExecuteNonQuery()
            End Using

Note que essa operação é extremamente simples. Ela segue exatamente o mesmo padrão de execução de comandos ADO.NET com outros bancos de dados (SQL Server, Access, MySQL, SQLite, etc).

A próxima operação que analisaremos é a inserção de dados na tabela de Clientes. Faremos a inserção de uma nova entrada utilizando um valor fixo para a coluna “Nome“:

                // C#
                using (var comm = new Oracle.DataAccess.Client.OracleCommand())
                {
                    comm.Connection = conn;
                    comm.CommandText = "INSERT INTO Cliente (Nome) VALUES ('Novo Cliente')";
                    comm.ExecuteNonQuery();
                }
            ' VB.NET
            Using Comm As New Oracle.DataAccess.Client.OracleCommand()
                Comm.Connection = Conn
                Comm.CommandText = "INSERT INTO Cliente (Nome) VALUES ('Novo Cliente')"
                Comm.ExecuteNonQuery()
            End Using

Em seguida, faremos a atualização do registro que acabamos de criar. Para isso, precisamos primeiramente descobrir qual foi o “Id” utilizado no registro que acabamos de criar. Descobriremos isso fazendo uma consulta pelo maior “Id” da tabela Cliente através de um “ExecuteScalar“. Com o “Id” em mãos, fazemos então a alteração no registro:

                // C#
                using (var comm = new Oracle.DataAccess.Client.OracleCommand())
                {
                    comm.Connection = conn;
                    comm.CommandText = "SELECT MAX(Id) FROM Cliente";
                    var clienteId = comm.ExecuteScalar();
                    if (clienteId != null && clienteId != DBNull.Value)
                    {
                        comm.CommandText = "UPDATE Cliente SET Nome = 'Novo Cliente Alterado' WHERE Id = :Id";
                        comm.Parameters.Add("Id", clienteId);
                        comm.ExecuteNonQuery();
                    }
                }
            ' VB.NET
            Using Comm As New Oracle.DataAccess.Client.OracleCommand()
                Comm.Connection = Conn
                Comm.CommandText = "SELECT MAX(Id) FROM Cliente"
                Dim ClienteId = Comm.ExecuteScalar()
                If (ClienteId IsNot Nothing And ClienteId IsNot DBNull.Value) Then
                    Comm.CommandText = "UPDATE Cliente SET Nome = 'Novo Cliente Alterado' WHERE Id = :Id"
                    Comm.Parameters.Add("Id", ClienteId)
                    Comm.ExecuteNonQuery()
                End If
            End Using

Note que, na parte da atualização, nós utilizamos a funcionalidade de parâmetros do ADO.NET. Diferente do SQL Server (onde os nomes dos parâmetros devem começar com arroba), os parâmetros nomeados no Oracle devem começar com “dois pontos” seguido do nome do parâmetro (por exemplo, “:Id“). Depois, na hora de adicionar os parâmetros no comando, basta utilizarmos o mesmo nome que definimos no meio da query (sem os dois pontos) e tudo deve funcionar corretamente. Confira o meu artigo sobre parâmetros do ADO.NET para saber porque você deve utilizar essa funcionalidade ao invés de concatenar valores nas suas sentenças.

Por fim, vamos conferir como podemos fazer para listarmos os registros de uma tabela. Com o ADO.NET puro, temos duas opções: DataReader ou DataAdapter. Veja só como fica o código:

                // C#
                using (var comm = new Oracle.DataAccess.Client.OracleCommand())
                {
                    comm.Connection = conn;
                    comm.CommandText = "SELECT * FROM Cliente";

                    Console.WriteLine("DataReader:");
                    using (var reader = comm.ExecuteReader())
                    {
                        while (reader.Read())
                        {
                            Console.WriteLine("Nome do Cliente: {0}", reader["Nome"]);
                        }
                    }

                    Console.WriteLine("DataAdapter:");
                    var adapter = new Oracle.DataAccess.Client.OracleDataAdapter(comm);
                    var dataTable = new System.Data.DataTable();
                    adapter.Fill(dataTable);
                    foreach (System.Data.DataRow row in dataTable.Rows)
                    {
                        Console.WriteLine("Nome do Cliente: {0}", row["Nome"]);
                    }
                }
            ' VB.NET
            Using Comm As New Oracle.DataAccess.Client.OracleCommand()
                Comm.Connection = Conn
                Comm.CommandText = "SELECT * FROM Cliente"

                Console.WriteLine("DataReader:")
                Using Reader = Comm.ExecuteReader()
                    While Reader.Read()
                        Console.WriteLine("Nome do Cliente: {0}", Reader("Nome"))
                    End While
                End Using

                Console.WriteLine("DataAdapter:")
                Dim Adapter As New Oracle.DataAccess.Client.OracleDataAdapter(Comm)
                Dim DataTable As New System.Data.DataTable()
                Adapter.Fill(DataTable)
                For Each Row As DataRow In DataTable.Rows
                    Console.WriteLine("Nome do Cliente: {0}", Row("Nome"))
                Next
            End Using

E, com isso, completamos todas as operações de CRUD no Oracle utilizando ADO.NET puro. Veja como ficou o código completo:

            // C#
            using (var conn = new Oracle.DataAccess.Client.OracleConnection("Data Source=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=localhost)(PORT=1521))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=XE)));User ID=dbuser;Password=dbuser;"))
            {
                conn.Open();

                // DELETE
                using (var comm = new Oracle.DataAccess.Client.OracleCommand())
                {
                    comm.Connection = conn;
                    comm.CommandText = "DELETE FROM Cliente";
                    comm.ExecuteNonQuery();
                }
                // INSERT
                using (var comm = new Oracle.DataAccess.Client.OracleCommand())
                {
                    comm.Connection = conn;
                    comm.CommandText = "INSERT INTO Cliente (Nome) VALUES ('Novo Cliente')";
                    comm.ExecuteNonQuery();
                }
                // UPDATE
                using (var comm = new Oracle.DataAccess.Client.OracleCommand())
                {
                    comm.Connection = conn;
                    comm.CommandText = "SELECT MAX(Id) FROM Cliente";
                    var clienteId = comm.ExecuteScalar();
                    if (clienteId != null && clienteId != DBNull.Value)
                    {
                        comm.CommandText = "UPDATE Cliente SET Nome = 'Novo Cliente Alterado' WHERE Id = :Id";
                        comm.Parameters.Add("Id", clienteId);
                        comm.ExecuteNonQuery();
                    }
                }
                // SELECT
                using (var comm = new Oracle.DataAccess.Client.OracleCommand())
                {
                    comm.Connection = conn;
                    comm.CommandText = "SELECT * FROM Cliente";

                    Console.WriteLine("DataReader:");
                    using (var reader = comm.ExecuteReader())
                    {
                        while (reader.Read())
                        {
                            Console.WriteLine("Nome do Cliente: {0}", reader["Nome"]);
                        }
                    }

                    Console.WriteLine("DataAdapter:");
                    var adapter = new Oracle.DataAccess.Client.OracleDataAdapter(comm);
                    var dataTable = new System.Data.DataTable();
                    adapter.Fill(dataTable);
                    foreach (System.Data.DataRow row in dataTable.Rows)
                    {
                        Console.WriteLine("Nome do Cliente: {0}", row["Nome"]);
                    }
                }
            }
        ' VB.NET
        Using Conn As New Oracle.DataAccess.Client.OracleConnection("Data Source=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=localhost)(PORT=1521))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=XE)));User ID=dbuser;Password=dbuser;")
            Conn.Open()

            ' DELETE
            Using Comm As New Oracle.DataAccess.Client.OracleCommand()
                Comm.Connection = Conn
                Comm.CommandText = "DELETE FROM Cliente"
                Comm.ExecuteNonQuery()
            End Using
            ' INSERT
            Using Comm As New Oracle.DataAccess.Client.OracleCommand()
                Comm.Connection = Conn
                Comm.CommandText = "INSERT INTO Cliente (Nome) VALUES ('Novo Cliente')"
                Comm.ExecuteNonQuery()
            End Using
            ' UPDATE
            Using Comm As New Oracle.DataAccess.Client.OracleCommand()
                Comm.Connection = Conn
                Comm.CommandText = "SELECT MAX(Id) FROM Cliente"
                Dim ClienteId = Comm.ExecuteScalar()
                If (ClienteId IsNot Nothing And ClienteId IsNot DBNull.Value) Then
                    Comm.CommandText = "UPDATE Cliente SET Nome = 'Novo Cliente Alterado' WHERE Id = :Id"
                    Comm.Parameters.Add("Id", ClienteId)
                    Comm.ExecuteNonQuery()
                End If
            End Using
            ' SELECT
            Using Comm As New Oracle.DataAccess.Client.OracleCommand()
                Comm.Connection = Conn
                Comm.CommandText = "SELECT * FROM Cliente"

                Console.WriteLine("DataReader:")
                Using Reader = Comm.ExecuteReader()
                    While Reader.Read()
                        Console.WriteLine("Nome do Cliente: {0}", Reader("Nome"))
                    End While
                End Using

                Console.WriteLine("DataAdapter:")
                Dim Adapter As New Oracle.DataAccess.Client.OracleDataAdapter(Comm)
                Dim DataTable As New System.Data.DataTable()
                Adapter.Fill(DataTable)
                For Each Row As DataRow In DataTable.Rows
                    Console.WriteLine("Nome do Cliente: {0}", Row("Nome"))
                Next
            End Using
        End Using

E como fica com o Entity Framework?

Agora que já vimos como fazer as operações CRUD no Oracle utilizando ADO.NET puro, vamos ver como conseguimos obter o mesmo resultado utilizando Entity Framework?

Primeiramente, temos que adicionar a referência para a biblioteca que implementa o suporte ao Entity Framework no Oracle. Poderíamos adicionar a referência diretamente para a dll que foi instalada no nosso computador (ao instalarmos o provider e as ferramentas de suporte ao Visual Studio do Oracle, a dll do Entity Framework para o Oracle também é instalada). Porém, se fizermos isso, teremos que ajustar o nosso arquivo app.config por conta própria.

Para evitarmos esse ajuste manual, vamos adicionar a referência para essa biblioteca utilizando o NuGet. Ao fazermos isso, o arquivo app.config será ajustado automaticamente com algumas configurações padrão, poupando um pouco do nosso trabalho:

Nesse exemplo, vamos trabalhar com Code First. Ou seja, temos que criar as classes de domínio no nosso projeto e o Entity Framework criará automaticamente as tabelas necessárias. No nosso caso, já temos a tabela de Clientes criada no banco, então, o Entity Framework deverá simplesmente detectar a sua existência e considerá-la nas consultas. A nossa única classe de domínio será a classe “Cliente“:

// C#
public class Cliente
{
    public long Id { get; set; }
    public string Nome { get; set; }
}
' VB.NET
Public Class Cliente
    Public Property Id As Long
    Public Property Nome As String
End Class

Em seguida, temos que criar a nossa classe de contexto do Entity Framework:

    // C#
    public class EfContext : System.Data.Entity.DbContext
    {
        public System.Data.Entity.DbSet<Cliente> Cliente { get; set; }
    }
' VB.NET
Public Class EfContext
    Inherits System.Data.Entity.DbContext

    Public Property Cliente As System.Data.Entity.DbSet(Of Cliente)
End Class

Com isso, nós já temos a base que precisamos para criar uma instância do contexto na nossa aplicação. Não esqueça de instanciar o contexto dentro de um bloco “using“. Dessa forma, ele será automaticamente descartado após a finalização do bloco:

            // C#
            using (var contexto = new EfContext())
            {

            }
        ' VB.NET
        Using Contexto = New EfContext()

        End Using

Se executarmos o nosso projeto após adicionarmos o código acima, nós receberemos o seguinte erro:

Nós recebemos esse erro porque nós não configuramos as informações do nosso banco de dados no arquivo app.config. Para que o nosso exemplo funcione sem dar erro, nós temos que alterar dois lugares do nosso arquivo app.config:

Primeiro, temos que ajustar a tag “dataSource“, onde o elemento “alias” deve conter o nome do nosso contexto (“EfContext“) e o elemento “descriptor” deve conter a nossa string de conexão. Além disso, temos que alterar a tag “connectionStrings“, onde o elemento “name” deve conter o nome do nosso contexto e o elemento “connectionString” deve conter a nossa string de conexão.

Veja só como ficou a minha tag “dataSource” após as alterações:

  <oracle.manageddataaccess.client>
    <version number="*">
      <dataSources>
        <dataSource alias="EfContext" descriptor="Data Source=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=localhost)(PORT=1521))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=XE)));User ID=dbuser;Password=dbuser;"/>
      </dataSources>
    </version>
  </oracle.manageddataaccess.client>

E aqui vai a minha tag “connectionStrings” após as alterações:

  <connectionStrings>
    <add name="EfContext" providerName="Oracle.ManagedDataAccess.Client"
      connectionString="Data Source=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=localhost)(PORT=1521))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=XE)));User ID=dbuser;Password=dbuser;"/>
  </connectionStrings>

Feito isso, se executarmos novamente a nossa aplicação, não receberemos mais nenhum erro. Isso quer dizer que o Entity Framework conseguiu localizar o nosso banco de dados e o contexto foi inicializado com sucesso.

Agora, da mesma forma que fizemos com o ADO.NET puro, vamos implementar o primeiro passo do nosso CRUD, que será a exclusão de todos os dados da tabela de Clientes. Para isso, nós fazemos um “foreach” na tabela de Clientes, removendo todos os registros e salvando as alterações:

                // C#
                foreach (var c in contexto.Cliente)
                    contexto.Cliente.Remove(c);
                contexto.SaveChanges();
            ' VB.NET
            For Each C In Contexto.Cliente
                Contexto.Cliente.Remove(C)
            Next
            Contexto.SaveChanges()

Porém, ao executarmos o nosso projeto, receberemos o seguinte erro:

Por padrão, o Entity Framework usa o “schema” chamado “dbo“. Ao trabalhar com o Oracle no Entity Framework, descobri nesta thread do StackOverflow que temos que alterar o schema padrão no contexto de forma que ele fique com o mesmo nome do usuário (no meu caso, “DBUSER“). Para isso, temos que fazer um override no método “OnModelCreating” do nosso contexto e, dentro desse método, temos que fazer uma chamada ao método “HasDefaultSchema“, passando o nome do usuário:

    // C#
    public class EfContext : System.Data.Entity.DbContext
    {
        public System.Data.Entity.DbSet<Cliente> Cliente { get; set; }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
            modelBuilder.HasDefaultSchema("DBUSER");
        }
    }
' VB.NET
Public Class EfContext
    Inherits System.Data.Entity.DbContext

    Public Property Cliente As System.Data.Entity.DbSet(Of Cliente)

    Protected Overrides Sub OnModelCreating(modelBuilder As Entity.DbModelBuilder)
        MyBase.OnModelCreating(modelBuilder)
        modelBuilder.HasDefaultSchema("DBUSER")
    End Sub
End Class

Será que depois desse ajuste a gente consegue rodar o projeto sem erros? Infelizmente não. Vamos analisar o próximo erro:

Hmm. O nome já está sendo usado? Que estranho. Vamos dar uma olhada no banco de dados novamente, dando um “refresh” nas tabelas para ver o que o Entity Framework aprontou:

Veja só. Além da nossa tabela “CLIENTE“, o Entity Framework tentou criar a tabela “Clientes” (note o “s” no final) e provavelmente deu algum conflito com a tabela “CLIENTE” quanto ao nome da trigger que faz o auto-incremento do “Id“. Isso acontece porque a pluralização de nomes de tabelas é habilitada por padrão no Entity Framework. Para desabilitá-la, temos que fazer um ajuste no nosso método “OnModelCreating“, removendo a convenção de pluralização do nosso contexto:

    // C#
    public class EfContext : System.Data.Entity.DbContext
    {
        public System.Data.Entity.DbSet<Cliente> Cliente { get; set; }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
            modelBuilder.HasDefaultSchema("DBUSER");
            modelBuilder.Conventions.Remove<System.Data.Entity.ModelConfiguration.Conventions.PluralizingTableNameConvention>();
        }
    }
' VB.NET
Public Class EfContext
    Inherits System.Data.Entity.DbContext

    Public Property Cliente As System.Data.Entity.DbSet(Of Cliente)

    Protected Overrides Sub OnModelCreating(modelBuilder As Entity.DbModelBuilder)
        MyBase.OnModelCreating(modelBuilder)
        modelBuilder.HasDefaultSchema("DBUSER")
        modelBuilder.Conventions.Remove(Of System.Data.Entity.ModelConfiguration.Conventions.PluralizingTableNameConvention)()
    End Sub
End Class

Agora vamos deletar a tabela “Clientes” que o Entity Framework criou erroneamente no nosso banco de dados e vamos executar a nossa aplicação novamente. Ao fazermos isso, receberemos o mesmo erro (dizendo que o nome já está sendo utilizado). O que será que aconteceu agora? Após um “refresh” nas tabelas, temos a seguinte situação:

Mas o que é isso? O Entity Framework não viu que a tabela “CLIENTE” já existia e acabou tentando criar uma outra tabela chamada “Cliente” (sem ser todas as letras maiúsculas)? Pois é. O Entity Framework trabalha com aspas simples ao redor de nomes de tabelas e campos. Isso faz com que o Oracle funcione em modo sensível a letras maiúsculas e minúsculas! Ou seja, para consertar isso, ou nós descartamos a tabela “CLIENTE” e passamos a trabalhar com a nova tabela “Cliente“, ou nós temos que fazer o mapeamento do nome da tabela e propriedades no método “OnModelCreating“:

    // C#
    public class EfContext : System.Data.Entity.DbContext
    {
        public System.Data.Entity.DbSet<Cliente> Cliente { get; set; }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
            modelBuilder.HasDefaultSchema("DBUSER");
            modelBuilder.Conventions.Remove<System.Data.Entity.ModelConfiguration.Conventions.PluralizingTableNameConvention>();
            modelBuilder.Entity<Cliente>()
                .Property(c => c.Id)
                .HasColumnName("ID");
            modelBuilder.Entity<Cliente>()
                .Property(c => c.Nome)
                .HasColumnName("NOME");
            modelBuilder.Entity<Cliente>().ToTable("CLIENTE");
        }
    }
' VB.NET
Public Class EfContext
    Inherits System.Data.Entity.DbContext

    Public Property Cliente As System.Data.Entity.DbSet(Of Cliente)

    Protected Overrides Sub OnModelCreating(modelBuilder As Entity.DbModelBuilder)
        MyBase.OnModelCreating(modelBuilder)
        modelBuilder.HasDefaultSchema("DBUSER")
        modelBuilder.Conventions.Remove(Of System.Data.Entity.ModelConfiguration.Conventions.PluralizingTableNameConvention)()
        modelBuilder.Entity(Of Cliente)() _
            .Property(Function(C) C.Id) _
            .HasColumnName("ID")
        modelBuilder.Entity(Of Cliente)() _
            .Property(Function(C) C.Nome) _
            .HasColumnName("NOME")
        modelBuilder.Entity(Of Cliente)().ToTable("CLIENTE")
    End Sub
End Class

Pronto! Agora sim o nosso código funcionará corretamente, considerando a tabela “CLIENTE“:

Veja só como fica o código completo para fazer todas as operações CRUD com o Entity Framework:

            // C#
            using (var contexto = new EfContext())
            {
                // DELETE
                foreach (var c in contexto.Cliente)
                    contexto.Cliente.Remove(c);
                contexto.SaveChanges();

                // INSERT
                contexto.Cliente.Add(new Cliente() { Nome = "Novo Cliente EF" });
                contexto.SaveChanges();

                // UPDATE
                var cliente = contexto.Cliente.First();
                cliente.Nome = "Novo Cliente EF Alterado";
                contexto.SaveChanges();

                // SELECT
                foreach (var c in contexto.Cliente)
                {
                    Console.WriteLine("Nome do Cliente: {0}", c.Nome);
                }
            }
        ' VB.NET
        Using Contexto = New EfContext()
            ' DELETE
            For Each C In Contexto.Cliente
                Contexto.Cliente.Remove(C)
            Next
            Contexto.SaveChanges()

            ' INSERT
            Contexto.Cliente.Add(New Cliente() With {.Nome = "Novo Cliente EF"})
            Contexto.SaveChanges()

            ' UPDATE
            Dim Cliente = Contexto.Cliente.First()
            Cliente.Nome = "Novo Cliente EF Alterado"
            Contexto.SaveChanges()

            ' SELECT
            For Each C In Contexto.Cliente
                Console.WriteLine("Nome do Cliente: {0}", C.Nome)
            Next
        End Using

Concluindo

Muitas vezes nós ficamos mal-acostumados quando trabalhamos com .NET e SQL Server. Nesse tipo de ambiente tudo normalmente funciona perfeitamente de primeira. Quando partimos para alguma outra tecnologia que não seja da Microsoft, aí começam a surgir os problemas. E foi isso que experimentamos na pele ao tentarmos utilizar o Oracle com C# e VB.NET no artigo dessa semana.

Não há dúvidas que o Oracle é um banco de dados importantíssimo, afinal de contas, como eu mencionei no começo do artigo, ele é atualmente o banco de dados relacional mais utilizado no mundo. Entretanto, podemos concordar que a sua configuração e utilização através do .NET não é lá tão simples assim, principalmente quando adicionamos um ORM como o Entity Framework no meio do caminho (cenário muito comum hoje em dia).

No artigo de hoje, você aprendeu a instalar o Oracle Database Express (versão gratuita do Oracle) e conheceu as suas limitações. Em seguida, eu te apresentei a ferramenta de administração da própria Oracle (o Oracle SQL Developer) que, apesar de não chegar nem perto do SQL Server Management Studio (na minha opinião), até que dá conta do recado. Por fim, você viu como instalar o provider e ferramentas de suporte ao Visual Studio, além de uma implementação bem simples de CRUD com ADO.NET puro e Entity Framework.

E aí, qual a sua opinião? Você acha que o SQL Server é mais simples de instalar e configurar? Já teve que trabalhar com o Oracle nos seus projetos? Passou pelos mesmos problemas que eu passei? Conte-nos mais detalhes na caixa de comentários!

Por fim, convido você a inscrever-se na minha newsletter. Ao fazer isso, você receberá um e-mail toda semana sobre o artigo publicado e ficará sabendo também em primeira mão sobre o artigo da próxima semana, além de receber dicas “bônus” que eu só compartilho por e-mail. Inscreva-se utilizando o formulário logo abaixo.

Até a próxima!

André Lima

Newsletter do André Lima

* indicates required



Powered by MailChimp

23 thoughts on “Utilizando o Oracle com C# e VB.NET

  • Marcelo Ramos disse:

    Olá André, sensacional esta matéria. Recomendo o TOAD Free como gerenciador do banco de dados MYSQL, mas existe também para Oracle no link http://www.toadworld.com/m/freeware/43

    Abraços!

    • andrealveslima disse:

      Olá Marcelo, obrigado pelo comentário!

      Não conhecia o TOAD, pareceu ser bem interessante.. Vou dar uma olhada nele assim que conseguir encontrar um tempinho.. Editei o artigo mencionando essa ferramenta e te dando os créditos.. Valeu pela dica! :)

      Abraço!
      André Lima

  • Lucas Alexandre de Almeida disse:

    Bom dia André, como vai?
    Quero te dar os parabéns pelo artigo. Hoje eu trabalho na minha empresa com .NET e Oracle 12c Standard. Essa brincadeira começou a dois anos atrás, e na época meu amigo não foi fácil encontrar todo material de forma organizada e bem explicativa como você fez no seu artigo. De vez em quando temos que desbravar as coisas..hehehe. Cara, continue produzindo materiais como esse, isso ajuda muito a nossa comunidade. E concordo com você, não podemos ficar só no .NET + SqlServer. Hoje é importante conhecermos outras tecnologias, até porque muitos estão utilizando Oracle a décadas, não dá pra chegar e pedir pra trocar o banco. Abraços

    • andrealveslima disse:

      Olá Lucas, muito obrigado pelo comentário! Fico feliz que você tenha gostado do artigo!

      O objetivo é esse mesmo.. Continuar escrevendo artigos bem detalhados, mostrando todos os problemas que podemos encontrar no meio do caminho.. Tem muito artigo simples demais por aí.. Acho que artigos mais detalhados acabam ajudando mais no processo de aprendizado.. Dá trabalho pra escrever, mas, eu gosto.. :)

      Um grande abraço e sucesso aí nos seus projetos!
      André Lima

  • Olá André, como vai?
    Acompanho seu blog, lendo todos os artigos postado. Eu trabalhei com Oracle durante alguns anos (uns 7 anos para ser mais específicos) e acho que todos encontram alguma dificuldade na integração com outras ferramentas, mas sempre acabamos dando um jeito para resolver essas dificuldades. Sempre defendi o Oracle com unhas e dentes, até que um dia um cliente optou por comprar a licença do SQL Server. Fiquei com muito receio, tenho que confessar, mas depois que eu vi todo o banco migrado e funcionando sem perder absolutamente nada na performance comecei a prestar mais atenção neste banco de dados Microsoft, fiquei muito empolgado depois com a facilidade que o SQL Server e seus gerenciadores proporcionam na Administração do Banco de Dados, sem falar da integração com os recursos do .Net (digo mais especificamente com o Entity Framework).
    Hoje tenho mais produtividade no desenvolvimento .Net fazendo as integrações de dados com o SQL Server!
    Atualmente é 95% SQL Server e 5% MySQL interagindo com a plataforma .Net, produtividade então nem se fala.

    • andrealveslima disse:

      Olá Adriano!

      Pois é.. A produtividade do .NET com o SQL Server nem se compara à do Oracle.. Com o .NET + SQL Server, tudo simplesmente funciona de primeira.. Acredito que o Oracle tenha o seu lugar, mas, para aplicações comerciais “normais”, não consigo ver um ponto em que o SQL Server não consiga atender tudo o que o Oracle oferece..

      É claro que é sempre bom estar por dentro de como as coisas funcionam no Oracle (pelo menos o básico).. Por isso que resolvi escrever e publicar esse artigo – para que quem esteja procurando iniciar no Oracle com o .NET não precise passar por esses mesmos desafios que passei quando eu estava escrevendo o artigo..

      Abraço!
      André Lima

  • Marcos Vinicius disse:

    Parabéns. ótimo artigo

  • Airton Ferreira disse:

    Olá André, tudo bem?

    O Juliano Rossi, colega aqui do trabalho, fez uma implementação onde utilizou o alias gerado na datasource na connection string, não havendo necessidade de repetir o código.

    Abraços e parabéns pelo artigo.

    • andrealveslima disse:

      Olá Airton, obrigado pelo comentário!

      Não entendi muito bem.. Como assim utilizou o alias gerado na datasource? Seria o alias definido no arquivo “tnsnames.ora”? Se sim, eu tô ligado como funciona.. Eu quis utilizar esse outro método porque achei mais flexível, uma vez que, com ele, nós não precisamos nos preocupar com o conteúdo do arquivo tnsnames..

      Agora, se for outra coisa, será que você poderia dar mais detalhes de como ficou o código? Fiquei curioso.. :)

      Abraço!
      André Lima

      • Airton Ferreira disse:

        Olá André, tudo bem?

        Acho que me expressei mal. Bom, seria desta forma. A única alteração, na verdade, é a inclusão do ALIAS no Data Source da tag connectionString com mesmo nome da tag dataSources.

        Abraços!

        Airton

        • Airton Ferreira disse:

          Desculpe…não estou conseguindo enviar o código.

          • andrealveslima disse:

            Olá Airton! Acho que entendi.. Não sei porque não está dando para colar o código no comentário.. Se quiser mandar para mim por e-mail (contato [arroba] andrealveslima [ponto] com [ponto] br), eu tento colar aqui..

            Abraço!
            André Lima

  • Edward Gómez disse:

    Buen día para todos,

    Gran articulo sobre Oracle, considero que los instaladores deben ser lo mas sencillos posible para que el usuario no tenga que lidiar con posibles errores o complejas configuraciones que a la final llevan al usuario a optar por otra opción.

    En lo personal uso MySQL y me he cambiado de Access a SQLite, me gusta MySQL debido a que tiene un instalador muy liviano en comparación a SQLServer que es muy usado por los programadores, ademas que su instalador es muy intuitivo, también considero que ya es hora que MySQL venga en Español, en cuanto Access puedo decir que es con la que la mayoría comienza, pero sin quitar merito a Access lo cierto es que SQLite tiene muchas ventajas que en lo personal me han gustado mucho y por eso uso SQLite desde ahora.

    Al final podemos decir que la elección de la base de datos termina siendo un gusto personal, con la que mas cómodo se sienta uno trabajando.

    Saludos desde Colombia.

    Un abrazo.

    • andrealveslima disse:

      Olá Edward!

      Sem dúvida, como você disse, no final das contas a escolha do banco de dados acaba sendo bastante afetada pelo gosto pessoal.. A não ser que o cliente exija a utilização de um banco de dados específico.. Dessa forma, é sempre bom estar pelo menos por dentro dos principais bancos de dados para não ser pego desprevenido..

      A propósito, achei muito boas as suas escolhas.. Gostei bastante quando dei uma brincada com o MySQL e SQLite (apesar de continuar preferindo o SQL Server, provavelmente por eu estar mais familiarizado com ele).. Definitivamente o SQLite é mais interessante, poderoso e portável que o Access.. Uma excelente escolha para aplicações de pequeno e médio porte..

      Um grande abraço e sucesso nos seus projetos!
      André Lima

  • Evandro Sereno disse:

    Boa tarde André,

    Parabéns pelo seu artigo. É de grande ajuda. Fiz o download da ferramenta que você indicou, porém, após selecionar todas as ferramentas que quero instalar é apresentado a seguinte mensagem de erro:

    [INS-50013] Erro no Oracle Developer Tools para Visual Studio .NET.
    Instale o Visual Studio antes de prosseguir com esta instalação.

    Estranho de mais essa mensagem porque estou com o Visual Studio Community 2017 instalado no meu note. Poderia me dar alguma ajuda?

    Abraços,

    Evandro Sereno

    • andrealveslima disse:

      Olá Evandro, muito obrigado pelo comentário!

      O problema é que a Oracle ainda não implementou o suporte ao Visual Studio 2017.. Acompanhe esta thread para saber mais informações:

      Oracle Developer Tools for Visual Studio 2017

      Infelizmente você só tem duas opções nesse caso: ou espera a Oracle implementar o suporte (que ela diz que deve sair “em breve”) ou instala o Visual Studio 2015 e trabalha com ele enquanto isso..

      Abraço!
      André Lima

  • Leandro Alves disse:

    Hoje, 10-03-2018, só consegui instalar o provider depois de baixar e instalar o VS2015. Na minha opinião, é grande descuido se tratando de uma empresa tão renomada como a Oracle.

    Quanto ao artigo, foi excelente todas as sua explicações. Muito obrigado por compartilhar do seu conhecimento.

    Abraços

    • andrealveslima disse:

      Olá Leandro!

      Realmente é uma piada né.. Mas, fazer o que.. Infelizmente isso está fora do nosso controle.. :(

      De qualquer forma, fico feliz que o artigo tenha te ajudado..

      Abraço!
      André Lima

  • Pedro Azevedo disse:

    Olá André, parabéns pelo artigo. Já te acompanho pelo youtube (me ajudou muito com os relatórios :D)

    O Newsletter tá com algum problema?? Já me cadastrei e não chegou o email…

    • andrealveslima disse:

      Olá Pedro, muito obrigado pelo comentário! Fico feliz por ter ajudado.. :)

      Quanto à newsletter, que eu saiba, está funcionando sim.. Pelo menos não tive nenhuma outra reclamação..

      Eu acabei de enviar um e-mail manual de boas vindas para você.. Depois me avisa se você recebeu..

      Abraço!
      André Lima

  • Ricardo Miranda disse:

    Andre, Boa Noite!!

    Perfeito artigo, funcionou corretamente.

Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *