Ultimamente estou usando uma abordagem diferente para a persistência. vinha adotando os pattern de ActiveRecord e Repository além do DataMapper popularmente conhecido como DAO. Aperfeiçoei com essa dica do CV no guj.
Apesar da persistência ser arquitetural e teoricamente não fazer parte do dominio dos seus processos de negócios, invariavelmente é a maior preocupação na construção de um software o “como” e “onde” um objeto tem que mudar seu estado persistido. Em outras palavras como isolar a persistência de seu domain model para que a transparência dessa operação diminua o código sem aumentar os pontos de manutenção com alta coesão e fraco acoplamento.

Estados do objeto
Os objetos do ponto de vista do modelo de um processo apresentam estados, como excluído, alterado e criado. Podemos adotar o conceito de Active Record no domain model e fazer com que seus objetos implementem uma interface que sem criatividade no momento chamarei de ActiveRecord:

public interface ActiveRecord {
	public void carregado();
	public void novo();
	public void alterado();
	public void excluido();
}

Podemos então criar uma classe abstrata seguindo o pattern Template Method para criar uma estrutura básica para todos nossos objetos que chamarei de AbstractActiveRecord:

public abstract class AbstractActiveRecord < t extends AbstractActiveRecord >
		implements ActiveRecord {

	public void carregado() {
		Repository.carregar(this);
	}

	public void alterado() {
		Repository.alterar(this);
	}
…
}

Resolvi chamar o Repository dentro do Template do ActiveRecord para deixar isolado os DAOs da aplicação de criar apenas um ponto de manutenção em comum.
O conceito de Repository deixa o sistema isolado da infraestrutura de persistência funcionando como um espécie de banco de dados em memória que os objetos se dirigem ao perguntar por alguém (Alguém esse referente a uma entidade do dominio).
Observe que as classes do meu sistema devem extender a classe AbstractActiveRecord e implentar a interface ActiveRecord, mas isso não é se prender a um framework, porque essas classes fazem parte do dominio apesar de existirem para resolver um problema arquitetural, elas são do meu sistema, e estão independente de infraestrutura porque são relativos do dominio de qualquer forma.
Uma entidade do meu sistema fica assim:

public final class Cliente extends AbstractActiveRecord implements ActiveRecord {
	private int id;
	private String nome;
	private String cpf;
	//gets e sets
}

O Shoes tinha me dado um conselho de usar o Repository junto com o Active Record e DataMapper a um tempo atrás para isolar o modelo da persistência principalmente na lista de entidades, exemplo:
Cliente cliente = RepositorioClientes.carregaListaClientes();
Mas eu resolvi criar um repositório genérico para todas as entidades e dentro dele inserir uma chamada a uma fábrica de DAOs apropriado dependendo do tipo o objeto. Código do meu Repository:

public abstract class Repository {
	public static void carregar(ActiveRecord record) {
		System.out.println("carregou quem? " + record.getClass().getName());
		//faz o trabalho de persistencia... pode fazer injeção etc...
		//pode chamar uma Fabrica para criar o DAO a partir da classe
		// FabricaDAO.criarDAO(record.getClass());
	}
...
}

realizando um teste simples para ver como se comportaria:

public class TransacaoTest extends TestCase {
	public void testTransacao(){
		Cliente christiano = new Cliente();
		christiano.setNome("christiano");
		christiano.setCpf("999.999.999-99");
		christiano.novo();
		assertEquals(1, christiano.getId());
		//acontece mais algumas coisas...
		//e lá pelas tantas...
		christiano.setNome("Christiano Martins");
		christiano.alterado();
		assertEquals("Christiano Martins", christiano.getNome());
	}
}

O resultado foi como esperado, o processo vai modificando o estado dos objetos durante a transação e tornando o código mais legível, evitando chamar DAO dentro do meu modelo ou misturar código de framework como Hibernate ao meu domínio.
Com exemplos simples em transação praticamente CRUD a coisa funciona legal, quando precisamos alterar ou pra Lazy Loading ou Eager Loading dependendo do padrão da aplicação (deixo como padrão lazy), passamos um parâmetro para a estrutura como por exemplo:

normal
Cliente cliente = new Cliente(10); // esse construtor já invoca a estrutura e carrega as informações
com lazy Loading
Cliente cliente = new Cliente(10, ActiveRecord.LAZY_LOADING);
...
Construtor normal:
	public Cliente(int id) {
		super();
		this.id = id;
		this.carregado();
	}
Construtor parametrizavel
	public Cliente(int id, int LOADED_PARAMETER) {
		super();
		this.id = id;
		this.carregado(LOADED_PARAMETER);
	}
...

De qualquer forma podemos criar uma estrutura de modelo do domínio do meu processo isolada da arquitetura tecnológica facilitando a manutenção com padrões de projetos simples, código mais enxuto e transparência nas transações.