DDD e o Entity Framework (ADO.NET)

watch_later 2 de jul de 2013
Introdução

DDD, o que significa Domain Driven Design, gerou uma série de novidades. Há uma série de artigos e posts sobre como DDD trabalha com esta ou aquela tecnologia. Ou como construir um aplicativo utilizando DDD e X? É natural que eu também tenha me interessado e decidi ver como ele trabalha com o Entity Framework.

Breve introdução ao Domain Driven Design
DDD é um conceito arquitetônico de criação de software. A idéia principal é que o projeto de um aplicativo deve ser baseado em um modelo, e não na tecnologia ou qualquer outra coisa. Isso deixa claro não só para os desenvolvedores, mas também para especialistas na área.

Domain Driven Design é baseado em cinco objetos:

Entidades: Estes são os objetos que representam o núcleo de uma aplicação. Eles expressam o negócio, e são compreendidos pelos clientes. O que é mais importante é que cada órgão tem uma identidade e é único dentro do sistema.
Objetos de valor: esses objetos não têm identidades e descrevem características.
Serviços: Contém a lógica que não pertencem a uma entidade particular.
Fábricas: Este é apenas um modelo bem conhecido, que cuida da criação de entidades.
Repositórios: Repositórios são usados ​​para entidades separadas e sua representação em um banco de dados. Eles contêm um código que é responsável pela interacção com um banco de dados.

Entity Framework
Apenas um par de palavras sobre o que o Entity Framework (EF) é , Segundo a Wikipedia, o Entity Framework não é nem mais nem menos do que um ORM. Não se deve precisar de um PhD para entender que a abordagem baseada em conjuntos de dados de lidar com persistência de dados nem sempre está funcionando bem, especialmente em grandes projetos. Na verdade, a EF é a primeira ORM da Microsoft (LINQ to SQL não conta).

É fácil adivinhar pelo nome do quadro que o conceito central da EF é ... a EntityObject. EntityObjects representar objetos que contêm informação que deve ser mantida. Para fazê-lo funcionar, há três modelos com base em XAML e arquivos de mapeamento que são usados ​​por EF para trabalhar com dados reais.


Do ponto de vista do usuário, a EF torna as tarefas de persistência muito simples. Visual Studio gera todas as classes EntityObject necessárias a partir de um banco de dados e, em vez de trabalhar com conjuntos de dados e criação de SqlConnections, o usuário trabalha com as classes que representam objetos de negócios.

DDD Entities vs EF EntityObjects
Quando alguém pensa em criar um novo aplicativo usando DDD e EF, a primeira idéia que ocorre é a utilização de EF EntityObjects como Entidades DDD.

EntityObjects são únicos e têm identidades, conforme exigido para entidades. No entanto, eles não podem ser separados do Entity Framework. De acordo com a abordagem DDD, objetos de domínio devem representar apenas a lógica de negócios, que não deve ser responsável por armazenar ou exibir-se ou qualquer outra coisa. Esse conceito também é conhecido como ignorância de Persistência, o que significa que os objetos de domínio são ignorantes de como os dados são salvos ou recuperados de uma fonte de dados.

Infelizmente , EF não é um  ORM PI, e não há nenhuma maneira de fazer EntityObjects independentes do framework. Seu código é auto gerado com base em um esquema de banco de dados e um arquivo de mapeamento. Teoricamente, é possível a criação de entidades "reais" e usar o EntityFramework apenas como uma camada de persistência de dados. No entanto, é absolutamente ridículo porque neste caso será necessário aplicar de novo todos os padrões de persistência fornecidas pela EF.

Assim, em termos de DDD, o Entity Framework atua como Repositórios e EntityObjects como suas entidades integradas. É, obviamente, uma solução viável, mas muitos preferem ter objetos de domínio que não sabem nada sobre uma fonte de dados subjacente.

Ignorância ao persistir
Ignorância ao persistir é um assunto que as pessoas vêm discutido há um bom tempo. Alguns pensam que é bom, alguns pensam que é bom, mas nem sempre é necessário e alguns acham ruim.

Estas são as restrições que um persistent-ignorant framework  não deve impor aos objetos de domínio do desenvolvedor:

1- Exigir herdar de uma classe base especificada diferente do objeto
2- Requerem o uso de um método de factory para criar uma instância deles
3- Exigir o uso de tipos de dados especializados para as propriedades, incluindo coleções
4- Exigir a implementação de interfaces específicas
5- Requerer o uso de construtores específicos de enquadramento
6- Requerer o uso de campos ou propriedades específicas
7- Proibir construções de aplicações específicas
8-Exigir escrever código RDBMS, como consultas ou chamadas de procedimento armazenado em um dialeto específico do provider.

Mesmo que seja bom ter a oportunidade de trocar os bancos de dados, nem todo mundo precisa dele. Um objetivo mais prático do PI é a capacidade de persistir  objetos de banco de dados de forma  mais fácil, o que simplifica os testes unitários.

Os defensores da separação dos objetos de domínio e lógica de persistência não estavam felizes pela abordagem sugerida no EF. Suas vozes foram ouvidas, e foi prometido que EF v2 compatível com PI.


Por enquanto, é possível utilizar uma solução intermediária disponível em EF. É o chamado pattern IPOCO.

IPOCO
POCO stands para Plain Old objeto DLR e IPOCO para interface POCO. POCOs são objetos que não contêm qualquer complicação,ou código de específico de framework. Por exemplo, EntityObjects em EF não são POCOs, porque há um monte de código específico ORM. IPOCO não é uma interface real, é um padrão que requer a implementação de interfaces em vez de derivar de objetos especiais para usar um ORM.

O primeiro passo da equipe do EF no caminho para o PI foi a introdução de compatibilidade IPOCO na versão atual do framework.

Há três interfaces a serem implementadas por classes personalizadas.

IEntityWithChangeTracker = para o controle de alterações
IEntityWithKey =  para expor a chave de identidade da entidade (opcional, mas não implementar esta interface provoca uma redução significativa da eficiência)
IEntityWithRelationships =  é exigido para entidades com associações

Se você decidir ir por este caminho e usar IPOCO em vez de classes geradas pelo EdmGen.exe, você deve estar ciente da quantidade de trabalho pela frente. Não só você vai ter que implementar as interfaces, mas também decorar suas classes com atributos específicos EDM , para fornecer a estrutura de metadados necessários. Além disso, você vai privar-se da conveniência de recurso automático de propriedades, porque cada propriedade terá a funcionalidade de controle de alterações. Basicamente, tudo que você vê em uma EntityObject gerado, você vai terá que fazer todo o resto sozinho.


Para entender melhor o código necessário, dê uma olhada no artigo do MSDN que tem um exemplo de implementação de todas as interfaces.

Projetando uma aplicação com EF
A falta de PI em EF não significa que "é inútil. Nem um pouco. É apenas uma abordagem diferente.

Vamos fingir que ainda estamos fazendo DDD, só os nossos objetos de domínio serão dependente da camada de banco de dados. Não é muito bom, mas vamos esperar que não vai precisar usar outro banco de dados no futuro previsível.

A primeira questão que se coloca é onde é que vamos colocar lógica específica de domínio? Como EntityObjects são gerados automaticamente, é uma má idéia estendê-los diretamente, em vez disso, podemos criar classes parciais que contêm tudo o que precisamos.

Não se esqueça que EntityFramework é mais do que um conjunto de classes de gerados automaticamente  Sua ObjectContext será o nosso Mapa de Identidade e Unidade de Trabalho, para que os nossos Repositório seja muito simples. Eles servirão como storages para todo o código interação com o banco. Ele vai anular as entidades do código que eles realmente não precisam, e dar como uma oportunidade para testa consultas em testes unitários.


Podemos realizar mais uma coisa que potencialmente nos ajudaria se nós decidicemoss mudar o ORM. Podemos criar as interfaces e fazer nossos objetos de entidade para implementá-las. Ele vai complicar a nossa vida um pouco, mas vamos ter a ilusão de "independência" e, quem sabe, provavelmente, ele vai ajudar um dia ...

Conclusão
Se a idéia  de usar PI não é crucial, pode-se dizer que é possível a utilização de EF e DDD juntos. Se é ... há sempre outras opções. Você pode alcançar um nível maior de abstração para objetos de domínio usando IPOCO, ou usando outro ORM (NHibernate é dito ser totalmente PI).