MauricioAniche:
Sérgio,
É nisso que eu queria chegar… Você injeta um IUnitOfWork no repositório. A minha dúvida é como é essa interface…
Algo do tipo resolveria, concorda?
public interface IUnitOfWork
{
void add(Object o);
void delete(Object o);
void update(Object o);
void persistAll();
}
Os Unit of Works de vocês tem algo a mais do que isso?
Esse é o padrão UnitOfWork tal como definido pelo Fowler. Na prática não encontro essa forma do padrão util.
Eu perfiro um versão um pouco diferente (que chamo de WorkUnit para não confundir).
abstract classs WorkUnit {
public abstract String getWorkResource();
public abstract void doLocks(WorkContext context);
public abstract void doWork(WorkContext context);
}
class WorkUnitExecutor{ // ponto de invocação dos trabalhos
public void execute (WorkUnit wu){
// faz queue da unidade conforme o recurso
WorkContext wc = new WorkContext (wu)
wc.execute();
}
}
class WorkContext {
@Inject DAO realDAO;
WorkDAO workDAO = new WorkDAO();
public void lockResource(String resource){
// faz o lock do recurso. controla locks anteriores.
// em caso de problema envia um OptimisticLockException.
}
execute(){
Transacion t= ...;
// joga workDAO no thread
try{
t.begin()
this.wu.doLocks(this);
this.wu.doWork(this);
workDAO.commitTO(daoReal);
t.commit();
} catch (){
t.rollback();
} finally {
releaseLocks();
// retira workDAO do thread
}
}
}
// uso
TransferWorkUnit wu = new TransferWorkUnit ( // parametros como contas, valores etc..);
WorkExecutor.getInstance().execute(wu);
class TransferWorkUnit extends WorkUnit {
public void doWork(WorkContext wc){
RepositoryA r = Repositories.getRepository(RepositoryA.class);
// faz algo com r
}
}
A ideia é que existe um objetivo do tipo comando (o WorkUnit) cuja execução é controlada através de um contexto. Ele pode usar esse contexto para fazer lock de recurso para controlar concorrencia ( pois a do banco não é suficiente já que pode nem existir um banco…).
O contexto usa um DAO especial. Este dao recebe todos as ações mas não as executa, apenas as coloca numa lista. Só quando acontece o commit é que o DAO joga os comandos para um DAO real.
Aqui é extremamente importante que o Repositorio possa ser injetado com o DAO. O repositorio é obtido através de um Registry que olha um threadLocal pelo DAO que está valendo. O WrokContext manipula esse threadlocal para que o Repositorio seja injetado com o DAO “dummy” . Dentro do codigo do workunit que é o que o programador escreve não ha diferença nenhuma já que ele está proibido de usar o DAO , tem que usar o respositório sempre que mexe com regras de negocio.
No fim tudo é revertido para a forma original.
Vc perguntou como eu fazia… :lol:
O meu WorkDAO seria o equivalente ao UnitOfWork do Fowler.
Repare que o UnitOfWork é um buffer do DAO , ou seja, as acções são iguais aos do DAO mas elas não acontecem realmente até que ha o commit final. Ele é um DAO com um método commit().
Nessa estrutura realmente o Repositorio tem que ser injetado com o DAO certo, especialmente em operação que manipulam os dados dentro de uma transação. E o UnitOfWork tem que ser injetado com o DAO real
Não faz sentido o Repositorio ter um UnitOfWork porque o UnitOfWork é opcional. Num select vc não usa UoW.
A ideia seria mais ou menos assim :
class MyService {
@Inject DAO daoReal
public void algumServiço(){
try{
UoWDAO dao = new UoWDAO(daoReal);
Repositorio r = new Repositorio(dao);
// faz algo com r
dao.commit();
} catch (){
// não faz dao.commit o que é equivalente a roolback
}
}
}
Nota: a annotaçao @Inject é só para dizer que deve ser injetado. Não é uma especificação de como a injeção deve acontecer. Básicamente significa “obtenha isto de alguma forma”