Otávio P. Coelho escreveu recentemente um post sugerindo o uso de singletons para manter o contexto de um Entity Data Model.
Venho utilizando essa estratégia há um bom tempo já para minhas aplicações que usam Linq to SQL e a partir do post do Otávio resolvi compartilhar um trecho de código que pode ser usado por todos.
Qual a vantagem de criar um singleton para isso? Bom, imagine que uma determinada rotina do seu código precise “atravessar” por vários métodos de instâncias de várias classes e imagine que essa “travessia” precise estar coberta por uma transação. Você não pode então criar uma instância do seu data context em cada método e passar um context já criado e passar como parâmetro é uma solução muito “feia” além de não permitir a separação das suas regras de negócio da camada de persistência.
Com um singleton, os métodos passam a “buscar” um data context já aberto, ou, se ainda não estiver criado, instancia um novo.
Usando os métodos CallContext e SetContext podemos manter o data context no contexto da aplicação, o que significa que em aplicações Windows Forms ele estará válido durante toda a execução do programa, ou no caso de aplicações WEB, durante o ciclo de vida de uma chamada Http Request.
Essa solução é transparente para aplicações WEB e Desktop, ou seja, se sua camada de negócios e/ou sua camada de persistência são usadas simultaneamente nas duas plataformas, a solução não precisa ser “ajustada”.
Exemplo abaixo, DataRepository é o nome do meu Data Context. Substitua pelo seu.
using System.Runtime.Remoting.Messaging;
namespace LINQToSQL
{
public class Helper
{
#region Privates
private static string _stringConexao = null;
private const string DATACONTEXT_ITEMS_KEY = "DBHelperContextKey";
private static DataRepository DataBaseContext
{
get
{
return (DataRepository)CallContext.GetData(DATACONTEXT_ITEMS_KEY);
}
set
{
CallContext.SetData(DATACONTEXT_ITEMS_KEY, value);
}
}
#endregion
#region Public and Protected Properties and Methods
/* a string de conexão você pode manter de várias formas
* talvez a mais prática seja recuperar diretamente via ConfigurationManager
*/
public static string StringConexao
{
get
{
return _stringConexao;
}
set
{
if (_stringConexao != null && _stringConexao.Equals(value))
return;
//Se já tem um DatabaseContext criado, elimina ele para
//que na próxima chamada seja reaberto com a nova string
//de conexao.
if (DataBaseContext != null)
{
CleanUp();
}
_stringConexao = value;
}
}
public static DataRepository Db
{
get
{
if (DataBaseContext == null)
{
DataBaseContext = new DataRepository(StringConexao);
}
return DataBaseContext;
}
}
public static System.IO.TextWriter Log
{
get
{
return Db.Log;
}
set
{
Db.Log = value;
}
}
public static void CleanUp()
{
if (DataBaseContext != null)
{
DataBaseContext.Dispose();
DataBaseContext = null;
}
}
#endregion
}
}