Atualmente, estamos usando o Entity Framework como um ORM em alguns aplicativos da Web e, até agora, ele nos serviu bem, pois todos os nossos dados são armazenados em um único banco de dados. Estamos usando o padrão de repositório e temos serviços (a camada de domínio) que os utilizam e retornam as entidades EF diretamente aos controladores do ASP.NET MVC.
No entanto, surgiu um requisito para utilizar uma API de terceiros (por meio de um serviço da Web) que nos fornecerá informações extras relacionadas ao usuário em nosso banco de dados. Em nosso banco de dados local de Usuários, armazenaremos um ID externo que podemos fornecer à API para obter informações adicionais. Há bastante informação disponível, mas por uma questão de simplicidade, uma delas se refere à empresa do usuário (nome, gerente, sala, cargo, local etc.). Essas informações serão usadas em vários locais em nossos aplicativos da web - em vez de serem usadas em um único local.
Então, minha pergunta é: qual é o melhor lugar para preencher e acessar essas informações? Como é usado em vários lugares, não é realmente sensato buscá-lo ad-hoc onde quer que o aplicativo seja usado - portanto, faz sentido retornar esses dados adicionais da camada de domínio.
Meu pensamento inicial era apenas criar uma classe de modelo de wrapper que contivesse a entidade EF (EFUser) e uma nova classe 'ApiUser' contendo as novas informações - e quando obtemos um usuário, obtemos o EFUser e, em seguida, obtemos o adicional informações da API e preencha o objeto ApiUser. No entanto, embora isso seja bom para obter usuários únicos, ele cai ao receber vários usuários. Não podemos acessar a API ao obter uma lista de usuários.
Meu segundo pensamento foi apenas adicionar um método singleton à entidade EFUser que retorna o ApiUser e preenchê-lo quando necessário. Isso resolve o problema acima, pois só o acessamos quando precisamos.
Ou o pensamento final era manter uma cópia local dos dados em nosso banco de dados e sincronizá-la com a API quando o usuário efetuar login. Isso é um trabalho mínimo, pois é apenas um processo de sincronização - e não temos a sobrecarga de acessar o banco de dados e a API sempre que queremos obter informações do usuário. No entanto, isso significa armazenar os dados em dois locais e também significa que os dados estão desatualizados para qualquer usuário que não esteja conectado há um tempo.
Alguém tem algum conselho ou sugestão sobre a melhor forma de lidar com esse tipo de cenário?
fonte
it's not really sensible to fetch it on an ad-hoc basis
-- Por quê? Por razões de desempenho?Respostas:
Seu caso
No seu caso, todas as três opções são viáveis. Acho que a melhor opção é provavelmente sincronizar suas fontes de dados em algum lugar em que o aplicativo asp.net não esteja ciente. Ou seja, evite sempre as duas buscas em primeiro plano, sincronize a API com o banco de dados silenciosamente). Então, se essa é uma opção viável no seu caso - eu digo.
Uma solução em que você faz a busca 'uma vez' como a outra resposta sugere não parece muito viável, pois não persiste a resposta em nenhum lugar e o ASP.NET MVC fará a busca para cada solicitação repetidamente.
Eu evitaria o singleton, não acho que seja uma boa ideia por muitas das razões usuais.
Se a terceira opção não for viável - uma opção é carregá-la com preguiça. Ou seja, faça com que uma classe estenda a entidade e atinja a API conforme a necessidade . Essa é uma abstração muito perigosa, já que é um estado ainda mais mágico e não óbvio.
Eu acho que realmente se resume a várias perguntas:
Uma ou duas palavras sobre separação de preocupações
Permitam-me argumentar contra o que Bobson está dizendo sobre a separação de preocupações aqui. No final das contas, colocar essa lógica em entidades como essa viola a separação de preocupações da mesma forma.
Ter esse repositório viola a separação de preocupações com a mesma lógica, colocando a lógica centrada na apresentação na camada de lógica de negócios. Agora, seu repositório está ciente das coisas relacionadas à apresentação, como como você exibe o usuário nos controladores asp.net mvc.
Em esta questão relacionada Pedi sobre como acessar as entidades directamente a partir de um controlador. Permitam-me citar uma das respostas aqui:
(Leia o resto da resposta, é realmente legal).
É ingênuo ignorar o fato de que há um banco de dados - existe um banco de dados e, por mais que você queira abstrair isso, ele não vai a lugar nenhum. Seu aplicativo estará ciente da fonte de dados. Você não poderá trocá-lo a quente. Os ORMs são úteis, mas vazam devido à complexidade do problema que resolvem e por várias razões de desempenho (como o Select n + 1, por exemplo).
fonte
Com uma separação adequada de preocupações , nada acima do nível do Entity Framework / API deve perceber de onde os dados vêm. A menos que a chamada à API seja cara (em termos de tempo ou processamento), o acesso aos dados que a utilizam deve ser tão transparente quanto o acesso aos dados do banco de dados.
A melhor maneira de implementar isso, então, seria adicionar propriedades extras ao
EFUser
objeto que carregasse preguiçosamente os dados da API, conforme necessário. Algo assim:Externamente, a primeira vez
CompanyName
ouJobTitle
é usado haverá uma única chamada de API feita (e, portanto, um pequeno atraso), mas todas as chamadas subsequentes até que o objeto é destruído será tão rápido e fácil como acessar banco de dados.fonte
Uma idéia é modificar o ApiUser para nem sempre ter as informações extras. Em vez disso, você coloca um método no ApiUser para buscá-lo:
Você também pode modificar isso levemente para usar o carregamento lento de dados extras, para que você não precise extrair UserExtraData do objeto ApiUser:
Dessa forma, quando você tiver uma lista, os dados extras não serão buscados por padrão. Mas você ainda pode acessá-lo enquanto percorre a lista!
fonte