Nous utilisons actuellement Entity Framework comme ORM dans quelques applications Web, et jusqu'à présent, cela nous convenait bien car toutes nos données sont stockées dans une seule base de données. Nous utilisons le modèle de référentiel et avons des services (la couche de domaine) qui les utilisent et renvoyons les entités EF directement aux contrôleurs ASP.NET MVC.
Cependant, une exigence est venue d'utiliser une API tierce (via un service Web) qui nous donnera des informations supplémentaires concernant l'utilisateur dans notre base de données. Dans notre base de données d'utilisateurs locale, nous stockons un ID externe que nous pouvons fournir à l'API pour obtenir des informations supplémentaires. Il y a beaucoup d'informations disponibles, mais pour des raisons de simplicité, l'une d'elles concerne l'entreprise de l'utilisateur (nom, responsable, chambre, titre du poste, emplacement, etc.). Ces informations seront utilisées à divers endroits dans nos applications Web - par opposition à être utilisées dans un seul endroit.
Ma question est donc la suivante: quel est le meilleur endroit pour remplir et accéder à ces informations? Comme il est utilisé à divers endroits, il n'est pas vraiment judicieux de le récupérer sur une base ad hoc partout où nous l'utilisons dans l'application Web - il est donc logique de renvoyer ces données supplémentaires à partir de la couche de domaine.
Ma pensée initiale était juste de créer une classe de modèle wrapper qui contiendrait l'entité EF (EFUser), et une nouvelle classe 'ApiUser' contenant les nouvelles informations - et lorsque nous obtenons un utilisateur, nous obtenons l'EFUser, puis les informations supplémentaires informations de l'API et remplissez l'objet ApiUser. Cependant, bien que ce soit bien pour obtenir des utilisateurs uniques, cela tombe lorsque vous obtenez plusieurs utilisateurs. Nous ne pouvons pas atteindre l'API lors de l'obtention d'une liste d'utilisateurs.
Ma deuxième pensée a été simplement d'ajouter une méthode singleton à l'entité EFUser qui renvoie l'ApiUser, et de la remplir en cas de besoin. Cela résout le problème ci-dessus car nous n'y accédons que lorsque nous en avons besoin.
Ou la dernière pensée était de conserver une copie locale des données dans notre base de données et de la synchroniser avec l'API lorsque l'utilisateur se connecte. C'est un travail minimal car c'est juste un processus de synchronisation - et nous n'avons pas la surcharge de frapper la base de données et l'API chaque fois que nous voulons obtenir des informations sur les utilisateurs. Cependant, cela signifie stocker les données à deux endroits et signifie également que les données sont obsolètes pour tout utilisateur qui ne s'est pas connecté depuis un certain temps.
Quelqu'un a-t-il des conseils ou des suggestions sur la meilleure façon de gérer ce type de scénario?
la source
it's not really sensible to fetch it on an ad-hoc basis
-- Pourquoi? Pour des raisons de performances?Réponses:
Ton cas
Dans votre cas, les trois options sont viables. Je pense que la meilleure option est probablement de synchroniser vos sources de données à un endroit dont l'application asp.net n'est même pas au courant. Autrement dit, évitez les deux récupérations au premier plan à chaque fois, synchronisez l'API avec la base de données en silence). Donc, si c'est une option viable dans votre cas - je dis de le faire.
Une solution où vous effectuez la récupération `` une fois '' comme le suggère l'autre réponse ne semble pas très viable car elle ne persiste pas la réponse n'importe où et ASP.NET MVC effectuera simplement la récupération pour chaque demande encore et encore.
J'éviterais le singleton, je ne pense pas que ce soit une bonne idée du tout pour plein de raisons habituelles.
Si la troisième option n'est pas viable - une option est de la charger paresseusement. Autrement dit, demandez à une classe d'étendre l'entité et faites-la toucher l'API au besoin . C'est une abstraction très dangereuse car c'est un état encore plus magique et non évident.
Je suppose que cela se résume vraiment à plusieurs questions:
Un mot ou deux sur la séparation des préoccupations
Permettez-moi de contester ce que Bobson dit à propos de la séparation des préoccupations ici. À la fin de la journée - mettre cette logique dans des entités comme ça viole tout aussi mal la séparation des préoccupations.
Le fait d'avoir un tel référentiel viole tout autant la séparation des préoccupations en plaçant la logique centrée sur la présentation dans la couche logique métier. Votre référentiel est maintenant soudain au courant des choses liées à la présentation, comme la façon dont vous affichez l'utilisateur dans vos contrôleurs mvc asp.net.
Dans cette question connexe, j'ai posé des questions sur l'accès aux entités directement à partir d'un contrôleur. Permettez-moi de citer l'une des réponses:
(Lisez le reste de la réponse, c'est vraiment sympa imo).
Il est naïf d'ignorer le fait qu'il existe une base de données - il existe une base de données, et peu importe à quel point vous voulez en résumer, cela ne va nulle part. Votre demande sera être au courant de la source de données. Vous ne pourrez pas le «remplacer à chaud». Les ORM sont utiles mais ils fuient en raison de la complexité du problème qu'ils résolvent et pour de nombreuses raisons de performances (comme Select n + 1 par exemple).
la source
Avec une séparation adéquate des préoccupations , rien au-dessus du niveau Entity Framework / API ne devrait même réaliser d'où viennent les données. À moins que l'appel d'API soit coûteux (en termes de temps ou de traitement), l'accès aux données qui l'utilisent doit être aussi transparent que l'accès aux données de la base de données.
La meilleure façon de l'implémenter serait alors d'ajouter des propriétés supplémentaires à l'
EFUser
objet qui chargeraient les données API paresseux selon les besoins. Quelque chose comme ça:Extérieurement, la première fois que l'un
CompanyName
ou l' autreJobTitle
est utilisé, il y aura un seul appel API (et donc un petit délai), mais tous les appels suivants jusqu'à ce que l'objet soit détruit seront aussi rapides et faciles que l'accès à la base de données.la source
Une idée est de modifier ApiUser pour ne pas toujours avoir les informations supplémentaires. Au lieu de cela, vous mettez une méthode sur ApiUser pour la récupérer:
Vous pouvez également modifier légèrement ceci pour utiliser le chargement paresseux de données supplémentaires, de sorte que vous n'ayez pas à extraire UserExtraData de l'objet ApiUser:
De cette façon, lorsque vous avez une liste, les données supplémentaires ne seront pas récupérées par défaut. Mais vous pouvez toujours y accéder tout en parcourant la liste!
la source