5. Estudo de caso com o Oracle Database Express Edition 11g Release 2
5.1. Instalação das ferramentas
As ferramentas a serem instaladas são as seguintes:
- o SGBD: [http://www.oracle.com/technetwork/products/express-edition/downloads/index.html];
- uma ferramenta de administração: EMS SQL Manager for Oracle Freeware [http://www.sqlmanager.net/fr/products/oracle/manager/download];
- um cliente Oracle para .NET: ODAC 11.2 Release 5 (11.2.0.3.20) com Oracle Developer Tools para Visual Studio: [http://www.oracle.com/technetwork/developer-tools/visual-studio/downloads/index.html].
Nos exemplos a seguir, o usuário “system” possui a senha “system”.
Vamos iniciar o Oracle [1] e, em seguida, a ferramenta [SQL Manager Lite for Oracle], com a qual administraremos o SGBD e o [2].
![]() |
- no [3], conectamo-nos a um banco de dados existente;
![]() |
- no [4], utilizamos o serviço Oracle XE para nos conectarmos;
- em [5], indicamos o nome do banco de dados XE;
- em [6], conectamo-nos como system / system;
- no [7], encerra-se o assistente;
![]() |
- em [8], faz-se o login no banco de dados;
- em [9], estamos conectados;
- como nos conectamos como o usuário system / system, que possui direitos estendidos, poderemos, por exemplo, gerenciar os usuários [10];
![]() |
- em [11], criamos um novo usuário;
- em [12], ele se chamará [RDVMEDECINS-EF];
- em [13], e terá a senha rdvmedecins;
- em [14], confirma-se a criação do usuário;
- em [15], o usuário foi criado;
![]() |
- em [16], o usuário [RDVMEDECINS-EF] também é um esquema de banco de dados;
- em [17], o usuário, tal como foi criado, não possui direitos suficientes. Concedemos esses direitos a ele por meio de um script SQL;
![]() |
- no [18], o script executado;
- em [19], vamos tentar fazer login com a identidade de [RDVMEDECINS-EF] para verificar o que ele pode fazer. Para isso, começamos registrando um novo banco de dados em [EMS Manager];
![]() |
- no [19], fazemos o login por meio do serviço XE;
- no [20], fazemos o login com a identidade RDVMEDECINS-EF / rdvmedecins;
- em [21], atribui-se um alias que reflete o nome do usuário conectado;
- em [22], faz-se o login no Oracle com as informações fornecidas;
![]() |
![]() |
- No [22], conseguimos nos conectar;
- em [23], tentamos criar uma tabela no esquema [RDVMEDECINS-EF];
- em [24], define-se uma tabela qualquer;
- no [25], validamos sua definição;
![]() |
- em [26], a tabela foi criada. Ela é excluída;
- em [27], ela foi excluída.
Agora que temos um usuário com permissões suficientes, vamos criar o projeto VS 2012, que criará as tabelas do esquema [RDVMEDECINS-EF] a partir da definição das entidades.
5.2. Criação do banco de dados a partir das entidades
Começamos duplicando a pasta do projeto [RdvMedecins-SqlServer-01] em [RdvMedecins-Oracle-01] e [1]:
![]() |
- em [2]; em VS 2012, excluímos o projeto [RdvMedecins-SqlServer-01] da solução;
![]() |
- em [3], o projeto foi excluído;
- em [4], adicionamos outro. Este está contido na pasta [RdvMedecins-Oracle-01] que criamos anteriormente;
![]() |
- em [5], o projeto carregado se chama [RdvMedecins-SqlServer-01];
- em [6], alteramos o nome para [RdvMedecins-Oracle-01]
![]() |
- em [7], adiciona-se outro projeto à solução. Esse projeto está contido na pasta [RdvMedecins-SqlServer-01] do projeto que havíamos excluído da solução anteriormente;
- no [8], o projeto [RdvMedecins-SqlServer-01] foi reintegrado à solução.
O projeto [RdvMedecins-Oracle-01] é idêntico ao projeto [RdvMedecins-SqlServer-01]. Precisamos fazer algumas alterações. No [App.config], vamos alterar a string de conexão e o [DbProviderFactory], que deve ser adaptado a cada SGBD.
<!-- cadeia de conexão com o banco de dados -->
<connectionStrings>
<add name="monContexte" connectionString="Data Source=(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=localhost)(PORT=1521)))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=XE)));User Id=RDVMEDECINS-EF;Password=rdvmedecins;" providerName="Oracle.DataAccess.Client" />
</connectionStrings>
<!-- o provedor de fábrica -->
<system.data>
<DbProviderFactories>
<remove invariant="Oracle.DataAccess.Client" />
<add name="Oracle Data Provider for .NET" invariant="Oracle.DataAccess.Client" description="Oracle Data Provider for .NET" type="Oracle.DataAccess.Client.OracleClientFactory, Oracle.DataAccess, Version=4.112.3.0, Culture=neutral, PublicKeyToken=89b483f429c47342" />
</DbProviderFactories>
</system.data>
- linha 3: o usuário e sua senha;
- linhas 6-11: o DbProviderFactory. A linha 9 faz referência a um DLL e a um [Oracle.DataAccess] que não temos. Ela é obtida com NuGet e [1]:
![]() |
- no [2], na área de pesquisa, digite a palavra-chave oracle;
- em [3], selecione o pacote [Oracle Data Provider] adequado. Trata-se do conector ADO.NET da Oracle;
![]() |
- em [4], a referência adicionada;
- em [5], no [App.config], é preciso inserir a versão correta do DLL. Ela pode ser encontrada nas propriedades do pacote.
No arquivo [Entites.cs], é preciso adaptar o esquema das tabelas que serão geradas. O esquema utilizado é o nome do usuário proprietário das tabelas.
[Table("MEDECINS", Schema = "RDVMEDECINS-EF")]
public class Medecin : Personne
{...}
[Table("CLIENTS", Schema = "RDVMEDECINS-EF")]
public class Client : Personne
{...}
[Table("RVS", Schema = "RDVMEDECINS-EF")]
public class Rv
{...}
[Table("CRENEAUX", Schema = "RDVMEDECINS-EF")]
public class Creneau
{...}
Configuramos a execução do projeto:
![]() |
- em [1], atribuímos outro nome ao assembly que será gerado;
- em [2], definimos também outro namespace padrão;
- em [3], indicamos o programa a ser executado.
Nesta fase, não há erros de compilação. Vamos executar o programa [CreateDB_01]. Recebemos a seguinte exceção:
Lembramos de ter tido o mesmo erro com MySQL. Isso está relacionado ao tipo do campo Timestamp das entidades. Fazemos a mesma modificação. Nas entidades, substituímos as três linhas
[Column("TIMESTAMP")]
[Timestamp]
public byte[] Timestamp { get; set; }
pelas seguintes:
[ConcurrencyCheck]
[Column("VERSIONING")]
public int? Versioning { get; set; }
Portanto, alteramos o tipo da coluna, que passa de byte[] para int?. Lembramos que, tanto para o SQL Server quanto para o MySQL, a coluna das tabelas que servia para gerenciar a concorrência de acesso recebia um valor do SGBD sempre que uma linha era inserida ou modificada. A partir de agora, vamos utilizar um campo de entidade que será um inteiro. No SGBD, utilizaremos procedimentos armazenados para incrementar esse inteiro em uma unidade sempre que uma linha for inserida ou modificada.
Fazemos a alteração acima nas quatro entidades e, em seguida, reexecutamos o aplicativo. Recebemos então o seguinte erro:
A linha 1 indica que o conector ADO.NET da Oracle não é capaz de excluir a base de dados existente. Vamos relembrar o que está acontecendo. O código do [CreateDB_01.cs] é o seguinte:
using System;
using System.Data.Entity;
using RdvMedecins.Models;
namespace RdvMedecins_01
{
class CreateDB_01
{
static void Main(string[] args)
{
// criando o banco de dados
Database.SetInitializer(new RdvMedecinsInitializer());
using (var context = new RdvMedecinsContext())
{
context.Database.Initialize(false);
}
}
}
}
A linha 15 aciona a execução da classe [RdvMedecinsInitializer] (linha 12). Ela é a seguinte:
public class RdvMedecinsInitializer : DropCreateDatabaseAlways<RdvMedecinsContext>
Ela deriva da classe [DropCreateDatabaseAlways], que tenta excluir e, em seguida, recriar o banco de dados. Alteramos a definição da classe para:
public class RdvMedecinsInitializer : CreateDatabaseIfNotExists<RdvMedecinsContext>
A criação do banco de dados só ocorre se ele não existir. Executamos novamente o [CreateDB_01.cs] e, dessa vez, não há mais erros. Porém, no [EMS Manager], constatamos que o banco de dados [RDVMEDECINS-EF] permaneceu vazio. Como o EF 5 encontrou um banco de dados existente, ele não realizou nenhuma ação. Ele só realiza alguma ação se o banco de dados não existir. A partir daí, entramos em um ciclo vicioso. De fato, a string de conexão para o SGBD é a seguinte:
<connectionStrings>
<add name="monContexte" connectionString="Data Source=(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=localhost)(PORT=1521)))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=XE)));User Id=RDVMEDECINS-EF;Password=rdvmedecins;" providerName="Oracle.DataAccess.Client" />
</connectionStrings>
Na linha 2, a string de conexão não utiliza o nome de um banco de dados, mas o nome de um usuário. Esse usuário deve existir.
Somos, então, levados a criar manualmente o banco de dados [RDVMEDECINS-EF] com a ferramenta [EMS Manager for Oracle]. Não descreveremos todas as etapas, mas apenas as mais importantes.
O banco de dados Oracle será o seguinte:
As tabelas
![]() |
As diferentes tabelas possuem as chaves primárias e estrangeiras que essas mesmas tabelas tinham nos dois exemplos anteriores. As chaves estrangeiras possuem, notadamente, os atributos ON, DELETE e CASCADE.
As sequências
Aqui foram criadas sequências Oracle. Trata-se de geradores de números consecutivos. São 5: [1].
![]() |
- em [2], vemos as propriedades da sequência [SEQUENCE_CLIENTS]. Ela gera números consecutivos de 1 em 1, começando em 1 até um valor muito grande.
Todas as sequências são construídas seguindo o mesmo modelo.
- [SEQUENCE_CLIENTS] será usada para gerar a chave primária da tabela [CLIENTS];
- [SEQUENCE_MEDECINS] será utilizada para gerar a chave primária da tabela [MEDECINS];
- [SEQUENCE_CRENEAUX] será usada para gerar a chave primária da tabela [CRENEAUX];
- [SEQUENCE_RVS] será utilizada para gerar a chave primária da tabela [RVS];
- [SEQUENCE_VERSIONS] será utilizada para gerar os valores das colunas [VERSIONING] de todas as tabelas.
Os gatilhos
Um trigger é um procedimento executado pelo SGBD antes ou depois de um evento (inserção, modificação, exclusão) em uma tabela. Temos 8 deles, [1]:
![]() |
Vamos examinar o código DDL do gatilho [TRIGGER_PK_CLIENTS] que alimenta a chave primária da tabela [CLIENTS]:
- linhas 1-5: antes de cada operação INSERT na tabela [CLIENTS];
- linha 6: a coluna [ID] assumirá o próximo valor da sequência [SEQUENCE_CLIENTS]. A chave primária terá, assim, valores consecutivos fornecidos pela sequência.
Os gatilhos [TRIGGER_PK_MEDECINS, TRIGGER_PK_CRENEAUX, TRIGGER_PK_RVS] funcionam de maneira semelhante.
Vejamos o código DDL do trigger [TRIGGER_VERSIONS_CLIENTS], que alimenta a coluna [VERSIONING] da tabela [CLIENTS]:
- linhas 1-2: antes de cada operação INSERT ou UPDATE na tabela [CLIENTS];
- linha 8: a coluna [VERSIONING] assumirá o valor seguinte da sequência [SEQUENCE_VERSIONS]. A coluna [VERSIONING] terá, assim, valores consecutivos fornecidos pela sequência.
Os gatilhos [TRIGGER_VERSION_MEDECINS, TRIGGER_VERSION_CRENEAUX, TRIGGER_VERSION_RVS] funcionam de maneira semelhante. As quatro colunas [VERSIONING] obtêm seus valores da mesma sequência.
O script de geração das tabelas do banco de dados Oracle [RDVMEDECINS-EF] foi colocado na pasta [RdvMedecins / databases / oracle]. O leitor poderá carregá-lo e executá-lo para criar suas tabelas.
Feito isso, os diversos programas do projeto podem ser executados. Eles fornecem os mesmos resultados que com o SQL Server, exceto pelo programa [ModifyDetachedEntities], que trava pelo mesmo motivo que travou com o MySQL. Resolve-se o problema da mesma maneira. Basta copiar o programa [ModifyDetachedEntities] do projeto [RdvMedecins-MySQL-01] para o projeto [RdvMedecins-Oracle-01]. Surge então um novo problema:
- linhas 1-4: o cliente destacado foi atualizado corretamente;
- linha 6: uma exceção conhecida. É aquela que ocorre quando se tenta modificar uma entidade sem ter a versão correta. No entanto, neste caso, não se pretendia modificar, mas sim excluir a entidade:
// exclusão de entidade fora do contexto
using (var context = new RdvMedecinsContext())
{
// aqui, temos um novo contexto vazio
// colocamos o cliente1 no contexto com o status “excluído”
context.Entry(client1).State = EntityState.Deleted;
// salvamos o contexto
context.SaveChanges();
}
EF 5 recusou-se a excluir client1 do banco de dados, pois client1 (linha 6) não tinha a mesma versão. Não havíamos encontrado esse problema com MySQL. Percebemos, aos poucos, que os conectores ADO.NET de diferentes SGBD apresentam pequenas diferenças. Corrigimos da seguinte forma:
using (var context = new RdvMedecinsContext())
{
// aqui, temos um novo contexto vazio
// colocamos o cliente1 no contexto para excluí-lo
context.Clients.Remove(context.Clients.Find(client1.Id));
// o contexto é salvo
context.SaveChanges();
}
e funciona.
5.3. Arquitetura multicamadas baseada em EF 5
Voltamos ao nosso estudo de caso descrito no parágrafo 2, página 7.
![]() |
Começaremos construindo a camada [DAO] de acesso aos dados. Para isso, duplicamos o projeto de console VS 2012 [RdvMedecins-SqlServer-02] em [RdvMedecins-Oracle-02] [1]:
![]() |
- em [2], excluímos o projeto [RdvMedecins-SqlServer-02];
![]() |
- em [3], adiciona-se um projeto existente à solução. Ele é obtido da pasta [RdvMedecins-Oracle-02] que acaba de ser criada;
- em [4], o novo projeto tem o mesmo nome daquele que foi excluído. Vamos alterar seu nome;
![]() |
- em [5], alteramos o nome do projeto;
- em [6], alteramos algumas de suas propriedades, como, neste caso, o nome do assembly;
- em [7], a pasta [Models] é excluída para ser substituída pela pasta [Models] do projeto [RdvMedecins-Oracle-01]. De fato, os dois projetos compartilham os mesmos modelos.
![]() |
- em [8], as referências atuais do projeto;
- em [9], foi adicionado o conector ADO.NET da Oracle com a ferramenta NuGet.
No arquivo [App.config], substitui-se as informações do banco de dados SQL Server pelas do banco de dados Oracle. Elas podem ser encontradas no arquivo [App.config] do projeto [RdvMedecins-Oracle-01]:
<!-- cadeia de conexão com o banco de dados -->
<connectionStrings>
<add name="monContexte" connectionString="Data Source=(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=localhost)(PORT=1521)))(CONNECT_DATA=(SERVER=DEDICATED)(SERVICE_NAME=XE)));User Id=RDVMEDECINS-EF;Password=rdvmedecins;" providerName="Oracle.DataAccess.Client" />
</connectionStrings>
<!-- o provedor de fábrica -->
<system.data>
<DbProviderFactories>
<remove invariant="Oracle.DataAccess.Client" />
<add name="Oracle Data Provider for .NET" invariant="Oracle.DataAccess.Client" description="Oracle Data Provider for .NET" type="Oracle.DataAccess.Client.OracleClientFactory, Oracle.DataAccess, Version=4.112.3.0, Culture=neutral, PublicKeyToken=89b483f429c47342" />
</DbProviderFactories>
</system.data>
Os objetos gerenciados pelo Spring também mudam. Atualmente, temos:
<!-- configuração do Spring -->
<spring>
<context>
<resource uri="config://spring/objects" />
</context>
<objects xmlns="http://www.springframework.net">
<object id="rdvmedecinsDao" type="RdvMedecins.Dao.Dao,RdvMedecins-SqlServer-02" />
</objects>
</spring>
A linha 7 faz referência ao assembly do projeto [RdvMedecins-SqlServer-02]. O assembly agora é [RdvMedecins-Oracle-02].
Feito isso, estamos prontos para executar o teste da camada [DAO]. Antes disso, é preciso preencher o banco de dados (programa [Fill] do projeto [RdvMedecins-Oracle-01]). O programa de teste é executado com sucesso.
Criamos o DLL do projeto, da mesma forma que foi feito para o projeto [RdvMedecins-SqlServer-02], e reunimos oconjunto de DLL do projeto em uma pasta [lib] criada em [RdvMedecins-Oracle-02]. Essas serão as referências do projeto web [RdvMedecins-Oracle-03] que se seguirá.
![]() |
Agora estamos prontos para construir a camada [ASP.NET] do nosso aplicativo:
![]() |
Vamos partir do projeto [RdvMedecins-SqlServer-03]. Duplicamos a pasta desse projeto em [RdvMedecins-Oracle-03] e [1]:
![]() |
- em [2], com o VS 2012 Express para a web, abrimos a solução da pasta [RdvMedecins-Oracle-03];
- em [3], alteramos tanto o nome da solução quanto o nome do projeto;
![]() |
- no [4], as referências atuais do projeto;
- em [5], as eliminamos;
- em [6], para substituí-las por referências ao DLL que acabamos de armazenar na pasta [lib] do projeto [RdvMedecins-Oracle-02].
Resta-nos apenas modificar o arquivo [Web.config]. Substituímos seu conteúdo atual pelo conteúdo do arquivo [App.config] do projeto [RdvMedecins-Oracle-02]. Feito isso, executamos o projeto web. Ele funciona. Não se esqueça de preencher o banco de dados antes de executar o aplicativo web.




























