We are currently using Entity Framework as an ORM across a few web applications, and until now, it has suited us well as all our data is stored in a single database. We are using the repository pattern, and have services (the domain layer) which use these, and return the EF entities directly to the ASP.NET MVC controllers.
However, a requirement has come up to utilise a 3rd party API (through a web service) which will give us extra information that relates to the user in our database. In our local User database, we will store an external ID which we can provide the to API to get additional information. There is quite a bit of information available, but for the sake of simplicity, one of them relates to the user's company (name, manager, room, job title, location etc). This information will be used in various places throughout our web apps – as opposed to being used in a single place.
So my question is, where is the best place to populate and access this information? As it is used in various places, it's not really sensible to fetch it on an ad-hoc basis wherever we use in the web application – so it makes sense to return this additional data from the domain layer.
My initial thought was just to create a wrapper model class which would contain the EF entity (EFUser), and a new 'ApiUser' class containing the new information – and when we get a user, we get the EFUser, and then get the additional info from the API, and populate the ApiUser object. However, whilst this would be fine for getting single users, it falls over when getting multiple users. We can't hit the API when getting a list of users.
My second thought was just to add a singleton method to the EFUser entity which returns the ApiUser, and just populate it when needed. This solves the above problem as we only access it when we need it.
Or the final thought was to keep a local copy of the data in our database, and synchronise it with the API when the user logs in. This is minimal work as it's just a synchronisation process – and we don't have the overhead of hitting the DB and API every time we want to get user information. However, these means storing the data in two places, and also means the data is out of date for any user that hasn't logged in for a while.
Does anyone have any advice or suggestions on how best to handle this kind of scenario?
Best Answer
Your case
In your case all three options are viable. I think that the best option is probably to sync your data sources someplace the asp.net application is not even aware of. That is, avoid the two fetches in the foreground every time, sync the API with the db silently). So if that's a viable option in your case - I say do it.
A solution where you make the fetch 'once' like the other answer suggests doesn't seem very viable since it doesn't persist the response anywhere and ASP.NET MVC will just make the fetch for every request over and over.
I'd avoid the singleton, I don't think it's a good idea at all for plenty of the usual reasons.
If the third option is not viable - one option is to lazy load it . That is, have a class extend the entity, and have it hit the API on a need to basis. That's a very dangerous abstraction though since it's even more magic and non-obvious state.
I guess it really boils down to several questions:
A word or two about separation of concerns
Allow me to argue against what Bobson is saying about separation of concerns here. At the end of the day - putting that logic in the entities like that violates separation of concerns just as bad.
Having such a repository violates separation of concerns just as bad by putting presentation centric logic in the business logic layer. Your repository is now suddenly aware of the presentation related things like how you display the user in your asp.net mvc controllers.
In this related question I've asked about accessing entities directly from a controller. Allow me to quote one of the answers there:
(Read the rest of the answer, it's really nice imo).
It's naive to ignore the fact there is a database - there is a database, and no matter how hard you want to abstract that, it's not going anywhere. Your application will be aware of the data source. You won't be able to 'hot swap it'. ORMs are useful but they leak because of how complicated the problem they solve is and for plenty of performance reasons (Like Select n+1 for example).