We have a similar setting for our site. We use Passport for our user database, and our website does not have a user table at all. This makes life much easier than having multiple duplicate data between the passport and our website. I will use our code as an example of what you are doing, and hopefully this makes sense.
Our site has a License object that looks like this (Java is not C #, but they are similar):
public class License { public String companyName; public List<User> users; }
The license table looks like this (cropped):
CREATE TABLE licenses ( id UUID NOT NULL, company_name VARCHAR(255) NOT NULL, PRIMARY KEY (id) );
The license identifies users who are associated with it using a connection table similar to this one (Passport uses UUIDs for user identifiers that make life simple again):
CREATE TABLE users_licenses ( users_id UUID NOT NULL, licenses_id UUID NOT NULL, PRIMARY KEY (users_id, licenses_id), CONSTRAINT users_licenses_fk_1 FOREIGN KEY (licenses_id) REFERENCES licenses (id) );
Then we can choose in any direction. If we know the user ID, we can request all of their licenses as follows:
select * from licenses where users_id = ?
Or, if we know the license identifier, we can ask all users who have access to the license:
select * from users_licenses where licenses_id = ?
Once we have one or more user IDs, we can call the Passport / api / user or / api / user / search endpoint to retrieve one or more user objects. We actually use the Passport Java Client ( https://github.com/inversoft/passport-java-client ), which forces the API to call us, and then returns a List<User> . This is what is stored in the License class on top. This code is as follows:
License license = licenseMapper.retrieveById(licenseId); List<UUID> userIds = licenseMapper.retrieveUserIdsFor(licenseId); ClientResponse<SearchResponse, Errors> clientResponse = passportClient.searchUsers(userIds); license.users = clientResponse.successResponse.users;
LicenseMapper is a MyBatis interface that executes SQL and returns License objects. C # ORMs use LINQ, but that would be similar.
The nice thing about this setup is that there is no user database table in our database that we need to synchronize. Everything is loaded from the passport through the API. We don't even care about performance. The passport is local and can execute thousands of user requests every second, so we always load data, not cache it.
The only part of your question that requires additional code handles connections when you search for users like name='John Doe' . The only way to handle this is to first query your user database, get all the identifiers, and then upload their invoices. This seems to be dangerous if you have a large user database, but still possible.
In our situation, it might look like this:
UserSearchCriteria criteria = new UserSearchCriteria().withName("John Doe"); ClientResponse<SearchResponse, Errors> clientResponse = passportClient.searchUsersByQueryString(criteria); List<User> users = clientResponse.successResponse.users; Set<License> licenses = new HashSet<>(); for (User user : users) { licenses.addAll(licenseMapper.retrieveByUserId(user.id)); }