Depois de muito tempo sem postar um artigo técnico (andei postando algumas dicas, mas nada muito relevante), resolvi escrever um hoje. Vamos ver o que sai!
Estou participando de um projeto na qual utilizamos o Entity Framework para criação ORM (ou MOR – Modelo Objeto Relacional) de acesso ao banco de dados. Durante o desenvolvimento o cliente nos informou que a string de conexão com o banco de produção nos seria passada apenas através de uma DLL. Ou seja, não teríamos uma string de conexão propriamente dita no arquivo .config, e sim apenas um “esboço” dela.
A Connection String com todos os parâmetros preenchidos fica na DLL, por isso, no arquivo de configuração fica uma constante {CONST_CONNECTIONSTRING} que será substituída pela ConnectionString real.
A DLL contém um método estático que retorna a string de conexão. Para simular, vamos imaginar uma ClassLibrary com uma classe parecida com essa:
public class ConnectionString { public static string GetConnectionString() { return "Data Source=.; Initial Catalog=TESTEEF; Integrated Security=True; MultipleActiveResultSets=True"; } }
Quando vamos criar uma instância do ObjectContext do Entity Framework, temos um construtor que nos permite passar a string de conexão que desejamos utilizar. Mas nesse caso, temos parte da string de conexão no arquivo de configuração e outra parte em uma DLL. Para resolver isso, fiz um outro método estático que “junta” as duas coisas:
public static string GetCompleteConnectionString(string strConnectionName) { string strConnectionString = string.Empty; try { strConnectionString = ConfigurationManager.ConnectionStrings[strConnectionName] .ConnectionString; // é necessário: using System.Configuration; } catch { strConnectionString = string.Empty; } if (string.IsNullOrEmpty(strConnectionString)) throw new Exception("ConnectionString não encontrada."); return strConnectionString.Replace("{CONST_CONNECTIONSTRING}", ConnectionString.ConnectionString.GetConnectionString()); }
Agora, para criar o ObjectContext usando a Connection String correta, basta usar o construtor que permite passar a string como parâmetro.
using (Entidades e = new Entidades (GerenciarConnectionString.GetCompleteConnectionString("Entidades"))) { }
Pronto, terminamos! Mas ainda tem um “porém”. Quando estava desenvolvendo pensei o seguinte: “Vou ter que passar a ConnectionString em todos os lugares onde crio uma instância do ObjectContext? E se em algum eu passar o nome da ConnectionString errado?”. Para resolver isso, criei um novo construtor para a classe que representa o ObjectContext na qual eu sempre pego a ConnectionString através do método GetCompleteConnectionString que mostrei acima. Isso só é possível pelo fato da classe que representa o ObjectContext ser partial.
A classe parcial com o novo construtor ficou assim:
public partial class Entidades : global::System.Data.Objects.ObjectContext { public Entidades(bool bolBuscarConnectionStringCorreta) : base(GerenciarConnectionString.GetCompleteConnectionString("Entidades"), "Entidades") { if (!bolBuscarConnectionStringCorreta) throw new Exception("Este construtor permite apenas TRUE."); this.OnContextCreated(); } }
Feito isso, basta usar este novo construtor para a criação das instâncias do ObjectContext.
using (Entidades e = new Entidades(true)) { }
É isso, galera! Espero que seja útil.
O código fonte pode ser baixado aqui.
Obrigado
Fabiano Muniz
Set 02, 2011 @ 10:34:12
Bom dia, estou pesquisando para iniciar um projeto novo aqui na empresa, penso em utilizar o Entity Framework, mas o sistema será multi-bancos, a minha pergunta é a seguinte, será necessário ter um Model.edmx para cada banco???
Fernando Ottoboni
Set 02, 2011 @ 17:15:32
Boa tarde, Fabiano.
Trabalho em um projeto que foi planejado para ser multi-bancos (SQLServer e ORACLE), e o que fizemos foi separar os modelos em DLLs diferentes (uma DLL para quando acessa ORACLE e outra para quando acessa SQLServer). Sendo assim, são dois modelos. O problema neste caso é que os modelos devem ser idênticos com relação aos tipos, ou seja, se você tiver um campo do tipo NUMERIC(1) no SQLServer ou NUMBER(1) no Oracle, nos modelos eles devem ser decimal (por exemplo). Creio que se os tipos das propriedades dos modelos forem diferentes você pode ter problemas.
Espero te ajudado.
Grato.
Marcone Ferreira
Fev 24, 2012 @ 15:39:51
Finalmente alguém postando soluções para problemas/casos do Mundo Real.
Obrigado. E parabéns pelo artigo de grande utilidade.
Fernando Ottoboni
Fev 24, 2012 @ 16:14:07
Obrigado.
Downloads do blog via 4Shared « Fernando Ottoboni
Jul 13, 2012 @ 15:54:11
Rafhael A C Andrade
Jul 25, 2012 @ 16:14:03
Parabéns.. ótimo artigo.
ranniere
Ago 24, 2012 @ 11:47:08
Como seria usando os parametros de metadata?
Mas não quero passar via connection e sim já deixar defenido no projeto da class library.
Fernando Ottoboni
Jul 04, 2013 @ 13:13:05
Você não conseguirá deixar definido em um arquivo de configuração da class library (DLL), pois o arquivo de configuração que valerá é o da aplicação principal.
Por exemplo: Imagine uma DLL que está sendo usada em um projeto do tipo Web Site. Quando em qualquer local do web site você precisar da Connection String, ele sempre buscará no web.config do web site e não da class library. Entendeu?
No caso do meu exemplo, a Connection String estava em HARDCODE e não em parâmetros metadata.
Obrigado por visitar o site! Abraço.
fernandofsan
Jul 11, 2013 @ 09:52:19
Ajudou bastante, obrigado pelo compartilhamento do conhecimento.
Alexandro Gotardo
Jul 14, 2014 @ 19:08:19
boa noite, não estou conseguindo fazer com que se passe o parametro para a instancia do data model, não sei o porque ele nao da essa opção
Fernando Ottoboni
Jul 18, 2014 @ 11:30:46
Você fez o reload do construtor do data model?