Authorize data access at database level - c#

From the question title you might guess what is this about. I'll try to describe what I currently have and what I want to archive.
Suppose an application that handles four entities: User, Team, Repository and Document. The relationships between those entities are:
Each user belong to zero or more teams.
Each document belong to one repository
An user may own zero or more repositories
Each repository can be created as public or private
The content of a public repository is visible to all users who share a team with the repository's owner.
A private repository is only visible to it's owner.
Accessing documents of an user is not a problem, those are all documents stored in repositories that he owns. But the thing get complicated because what I really need is all documents visible to an user, this is all it's documents plus those documents other people made public and share a team with him.
Currently I'm enforcing this authorization mechanism in the Data Access Layer. This implies fetching all documents and do some filtering following rules above. I'm aware that this implementation is not scalable and I wonder if I can improve my database model by moving the authorization logic to the database. This way the filtering will be done by the DB engine and only requested entities will be returned to the client code.
This question is not tied to an specific implementation, but I'll tag it for the specific tools I'm using. Maybe it can be useful for someone's answer.

First let me explain why using entity framework (or another ORM tool) is more elegant than using stored procedures.
Stored Procedures are evil. That's why. As the link explains in detail, stored procedures tend to grow as a second BL and are therefore difficult to maintain. A simple task as renaming a column will become a big task when this column is used in multiple stored procedures. When you use a ORM tool, visual studio will do most of the work for you.
That said brings me to the second advantage of entity framework. You can compose your query by using your favorite .net language. Entity framework will not execute your query directly. You control when the query will be executed as you can read here. When doing this entity framework will compile your Linq statements to a complete tsql statement and run this against the database. So there is absolutely no need to fetch all data and loop through each record.
Tip: Move your cursor over the variable name and ef will give you a preview of the TSQL statement it will compile.
So how should your Linq query look like? I composed a test database based on your description and made an entity framework (ef6) model of it which looks like:
This Linq query will do what you want, at least as I understood your question correctly.
private IEnumerable<Document> GetDocumentsOfUser(Guid userId)
{
using (var db = new DocumentRepositoryEntities())
{
// Get owned repositories by the user
var ownedRepositories = db.Repositories
.Where(r => r.Owner.UserId == userId);
// Get all users of teams the user belongs to
var userInOtherTeams =
db.Users.Where(u => u.UserId == userId)
.SelectMany(u => u.Teams)
.SelectMany(t => t.Users);
// Get the public repositories owned by the teammembers
var repositoriesOwnedByTeamMembers =
userInOtherTeams.Where(u => u.Repositories.Any())
.SelectMany(u => u.Repositories)
.Where(r => !r.Private);
// Combine (union) the 2 lists of repositories
var allRepositories = ownedRepositories.Concat(
repositoriesOwnedByTeamMembers);
// Get all the documents from the selected repositories
return allRepositories.SelectMany(r => r.Documents)
.Distinct()
.ToArray(); //query will be composed here!
}
}
Note that the linq statement will be compiled to a TSQL select statement when the call to .ToArray() is made.

Based on your description, the goal is to find all of the repositories that the user currently has access to, then retrieve the documents from each of those repositories.
If this were my implementation, I would add a stored procedure to the database that accepts the current user's ID, then gathers the list of accessible repositories into a local table variable, then select from the documents table where the repository for the document is in the list of accessible repositories.
DECLARE
#Teams TABLE (TeamID UNIQUEIDENTIFIER NOT NULL PRIMARY KEY (TeamID))
DECLARE
#Repositories TABLE (RepositoryID UNIQUEIDENTIFIER NOT NULL PRIMARY KEY (RepositoryID))
/* Get the list of teams the user is a member of */
INSERT INTO #Teams
SELECT Teams.TeamID
FROM Teams INNER JOIN TeamUsers ON Teams.ID = TeamUsers.TeamID
WHERE TeamUsers.UserID = #UserID
/* Get the list of repositories the user shares a team member with */
INSERT INTO #Repositories
SELECT RepositoryID
FROM Repositories
WHERE OwnerID = #UserID
OR (OwnerID IN (SELECT DISTINCT TeamUsers.UserID
FROM TeamUsers INNER JOIN #Teams ON TeamUsers.TeamID = #Teams.TeamID)
AND IsShared = 1)
/* Finally, retrieve the documents in the specified repositories */
SELECT Documents.*
FROM Documents INNER JOIN #Repositories ON Documents.RepositoryID = #Repositories.RepositoryID

While the answer competent_tech suggests is valid, and good if your need is a one-off, what you would ideally want to do is implement your authorization requirements in a dedicated layer, in an externalized fashion. Reasons to do this include:
easier to maintain a decoupled architecture
you can update your authorization without touching your application and/or database
you do not need SQL / stored procedure knowledge
you can report more easily on what authorization is applied where: this is important if you have auditors breathing down your neck.
To achieve externalized authorization (see here for a Gartner report on the topic), you need to consider attribute-based access control (ABAC - see here for a report on ABAC by NIST) and the eXtensible Access Control Markup Language (XACML - more info here) as a means to implement ABAC.
If you follow the ABAC approach you get:
a clean, decoupled architecture with the notion of
an enforcement point or interceptor that will sit between your application and your database (in the case of ABAC applied to databases)
an authorization decision engine that reaches decisions and will produce a filter statement (a WHERE clause in the case of a SQL database) that the enforcement point will append to the original SQL statement
a policy-based and attribute-based authorization model whereby you can write authorization requirements in easy-to-understand statements instead of procedures, PL-SQL or other SQL artefacts. Examples include:
*a user can edit a document they own
a user can view documents if the user's team == the document's team
a user can view documents of another team if and only if the documents are marked as public
a user with the role editor can edit documents that belong to their team if and only if the document state is draft*
In the above examples, the user type, the resource type (document), the action (view, edit), the document's team, the user's team, and the document's visibility (private or public) are all examples of attributes. Attributes are the lifeline, the building blocks of ABAC.
ABAC can easily help you implement your authorization requirements from the simplest ones to the more advanced ones (such as can be found in export regulations, compliance regulations, or other business rules).
One neat benefit of this approach is that it is not specific to databases. You can apply the same principle and policies to home-grown apps, APIs, web services, and more. That's what I call the any-depth architecture / approach to externalized authorization. The following diagram summarizes it well:
The PDP is your centralized authorization engine.

Related

WCF data service permission on individual table columns instead of on whole entities

Note the bounty is asking about the edited portion of this question. First part is describing the problem
I have a table
Customer
-----
Name
Address
SocialSecurity
Phone
Etc....
I have another table called
Permissions
-----
IdOfUser
Can_C_Address
Can_R_Address
Can_U_Address
Can_D_Address
Can_C_Phone
Can_R_Phone
Can_U_Phone
Can_D_Phone
Etc...
note CRUD stands for create, read, update and delete
How can I make sure at the server side that a user query the database as:
contex.Customers.ToList();
pretend the user that made that request to the wcf data service had no permission to see the social security. I will like that list to return with null social security numbers. How can I do that?
It is a lot of work to separate each property/tableColumn into a different entity. For example having CustomerPhone, CustomerSocial, etc all as different entities.
---------------------------------------- Edit --------------------------------------
I found a weird solution! I do not know if it is safe though. Here it is:
Lets say I have an entity called Users. Users have a phone number, social security, address etc. My problem was that I wanted to hide the social security when someone queried the database for example. To solve that problem what I did was I CREATED AN OPERATION/METHOD WITH THE SAME NAME AS THE ENTITY In other words I added the method:
[WebGet]
public IEnumerable<Data.Sub.User> Users()
{
return this.CurrentDataSource.Users.ToList().Select(x => { x.SocialSecurity = ""; return x; });
}
Then on my client side when I did:
var context = new Data.DatabaseReference.MyEntity();
context.Users.ToList(); // WHEN I INVOKE THAT METHOD I SEE THAT I NEVER GET SOCIAL SECURITY!
Is it safe to take this approach?
You have four options and none of them is going to be fun.
1) If you are using the reflection provider handle the security at the root query. If it needs to be dynamic you will probably end up using ExpressionTrees to do the projection.
2) Create a custom data service provider - http://blogs.msdn.com/b/alexj/archive/2010/01/07/data-service-providers-getting-started.aspx If you are using Entity Framework you will need to also modify the expression tree and remove all their null projections they add when using a custom provider. This isn't for the faint of heart.
3) Intercept the IQueryable and using an ExpressionVisitor remove or replace any properties that shouldn't be projected. For example of how to intercept the query you can see what you need to do wrap IQueryable here http://blogs.msdn.com/b/vitek/archive/2012/01/07/projections-in-custom-providers-simple-solution.aspx. There was a Microsoft blog on how to intercept IQueryable and replace all the constants with properties so EF would send parameters that was good but I can't find it right now.
4) Switch from WCF Data Services over to Web API where you have more control. From this blog is what they are recommending anyways http://blogs.msdn.com/b/odatateam/archive/2014/03/27/future-direction-of-wcf-data-services.aspx
That's if you just want to do it for the read in crud. Besides #2 that doesn't really touch the create, update and delete part of CRUD.
Update
For option #3 you can read how to do it on my blog http://code.msdn.microsoft.com/Entity-Framework-a958cffb/sourcecode?fileId=95130&pathId=263687793

How to retrieve domain objects on indirect references? (when an entity has the Id of another entity, instead of a direct reference)

Vaughn Vernon has a series of pdfs that suggests to use indirect references to link related entities together. This way, Entity A would have a list of Entity B Ids instead of references to them. This avoids performance and scalability issues and also let's you focus on consistency boundaries.
My problem comes with traversing such a type of indirect reference to be able to perform domain logic.
Say I have Group, User and Authorizations. All three are entities and also their own aggregate. They can each be modified simultaneously from one another, and therefore are not part of a consistency boundary. They relate to each other in the way that Users are in Groups and Groups are Authorized for things.
I need domain logic that retrieves me the list of things a User is Authorized to. Ideally, I feel like this logic should be on the User as User.GetAuthorizations(); But I'm willing to move this somewhere else if it feels more appropriate.
The problem is that, no matter where I put this logic I will need to:
Get the Groups of a User.
For each of the user's groups, get
the given Authorizations.
Perform the merge logic of those
Authorization.
Return the Authorizations as they fit the User.
How should I therefore implement User.GetAuthorizations(); in a DDD context which uses Repositories for data access?
By this I mean that I want to know how I should retrieve the indirect reference and traverse it inside my method.
Here is an example:
public class UserApplicationService
{
public IEnumerable<Authorization> GetUserAuthorizations(string userId)
{
User user = _userRepo.Find(userId);
IEnumerable<Group> groups = _groupRepo.FindMany(user.GroupIds);
List<Tuple<Group, List<Authorization>>> groupAuths = new List<Tuple<Group, List<Authorization>>>()
foreach(Group group in groups)
{
List<Authorization> auths = _authorizationRepo.FindMany(group.AuthorizationIds).ToList();
Tuple<Group, List<Authorization>> groupAuth = new Tuple<Group, List<Authorization>>(group, auths);
groupAuths.Add(groupAuth);
}
return user.GetAuthorizations(groupAuths);
}
}
IEnumerable<Authorization> User.GetAuthorizations(List<Tuple<Group, List<Authorization>>> groupAuths)
{
// merge logic would be here
}
In this case, I retrieve in an Application Service the groups of the User and the Authorizations of all of those groups and I pass it to the User.GetAuthorizations method. I find this quite cumbersome, and if the relationship would be nested deeper, it would become even more cumbersome.
I wonder what other approach would there be that respect the DDD approach? How is this normally done?
Time has passed since asking this, and I've furthered my understanding to the point where I feel confident in answering this myself.
I need domain logic that retrieves me the list of things a User is Authorized to. Ideally, I feel like this logic should be on the User as User.GetAuthorizations(); But I'm willing to move this somewhere else if it feels more appropriate.
This is where lies the entire problem of my question, I want retrieval logic, and I'm mistakenly thinking it must go in my domain.
In DDD, you have a domain model that tries to encapsulate the ubiquitous language of the application, but only for purposes of data change. Those entities, value objects and aggregate roots should encapsulate transactional context.
When you want to get information, you bypass all that. Query your data directly, and get exactly the info you want in the form you need.
The problem is that, no matter where I put this logic I will need to:
Get the Groups of a User.
Perform the merge logic of those Authorization.
Return the Authorizations as they fit the User.
How should I therefore implement User.GetAuthorizations(); in a DDD context which uses Repositories for data access?For each of the user's groups, get the given Authorizations.
This was missing the point. The proper way to do this is have an application service that has a method GetAuthorizations, like in my example, but this method should never use the Repository and never use the Aggregate Roots User, Group and Authorization. Instead, it should use a second abstraction, which is a query layer for retrieval of persistence data, which returns it's own type of entities that better match the query. So GetAuthorizations could retrieve objects of type AuthorizedUser. It would implement the merge logic as part of the querying process.
First of all - make sure that customer actually needs grouping of users for authorization rules definition. If not, your approach is an overkill and consider defining authorization rules in static fashion.
Another approach would be to make UserAuthorization entity that gets properly mutated for changes like 'user group has changed', 'authorization deleted' etc. Then it would be simple as asking authorization rules list for a user.

Entity Framework with multiple databases

Is there anyway to map multiple SQL Server databases in a single EF context? For instance I'm trying to do something like this
select order from context.Orders
where context.Users.Any(user => user.UserID == order.UserID)
And I'd like to get generated SQL along the lines of:
select .. from store.dbo.order where userID in
(select userID from authentication.dbo.user)
and note that the database names are different - store in one place, authentication in the other.
I've found a few articles that deal with multiple schema ('dbo' in this case), but none dealing with multiple database names.
As a potential workaround, you could create a view of the table from the second database in the first database and point your mappings to the view.
I'm pretty sure this isn't possible. The context derives from DbContext.
A DbContext instance represents a combination of the Unit Of Work and Repository patterns such that it can be used to query from a database and group together changes that will then be written back to the store as a unit. DbContext is conceptually similar to ObjectContext.
Configuration (connection string, schema, etc) for a DbContext is specific to a single database.
It's not possible. A notion of context is below notion of a database, and allowing this would probably be a bad practice. Allowing such a thing could cause developers to forget that they are dealing with two databases, and to take care about all performance implications that come from that.
I imagine you should still be able use two contexts and write elegant code.
var userIds = AuthContext.Users
.Where(user => user.Name = "Bob")
.Select(user => user.UserId)
.ToList();
var orders = StoreContext.Orders
.Where(order => userIds.Contains(order.UserId))
.ToList()
First execute query on authentication database context, in order to provide parameters for second query.

Data Entities > Domain Objects > ViewModels, each with drastically different data structures

This is sort of a generic question in regards to mapping between data entities, domain objects, and ViewModels. I may not be asking it right but hopefully I can make some sense of it. Below is a simplified problem.
Pretend I have an Entity Framework model which maps 1:1 to my database tables, but my domain objects may not be identical, and my ViewModel is drastically different again. As a pseudo-example:
Database/EF Entities:
MembershipAccount
MembershipAccountExtraInfo
Domain:
Account
Profile
Preferences
ViewModel:
UserProfileModel
Let's say I need to display a UserProfileModel which has: Username (from MembershipAccount), SignupDate (from MembershipAccount), FullName (from MembershipAccountExtraInfo), and TimeZone (from MembershipAccountExtraInfo)
What sort of relationships might I need here, and what sort of mapping mechanisms? Is it common to have something like an AccountMapper that takes both a MembershipAccount and MembershipAccountExtraInfo and returns an Account? I'm a bit stuck on the mapping when several objects are needed to create a single domain entity, and vice versa.
If it helps: I'm designing an API for managing User Accounts, User Profiles, User Preferences, etc. but the database tables are all over the place. A single User Profile might need to be created from data spanning 4-5 tables and 2 databases. There is no 1:1 mapping between my database tables and any (logical) domain objects.
Thanks!
I like to work keeping my domain objects as close to the objects that they represent as possible. What I mean by this is that if an account has preferences, then the domain Account object should contain a Preferences property, most likely represented by a collection of Preference objects. If nothing else, this helps the users understand the data structure of the application easily.
As for constructing the view models, that's the easiest bit... you add just properties for anything that is required. What types of properties you would need would really depend on how you have structured your domain objects.
If your view has the requirements that you mentioned in your question and you modelled your domain objects closely on the objects that they represent, then by the sounds of it, you would just need an Account object because that would contain the Preference and Profile objects inside it.
Finally, the only 'mapping' that needs to be done can be done with a LinQ query using the Entity Framework. It is at this point that I join the tables and pull whatever data that I need for whichever object I am working on. Here is an example of instantiating objects from data from three tables (using LinQ2SQL):
public AudioTracks GetAudioTracks(AudioTrackSearchOptions searchOptions)
{
AudioTracks audioTracks;
using (MidasDataContext dataContext = DataContext)
{
audioTracks = new AudioTracks(
from audioTrack in dataContext.DbAudioTracks
join masterTrack in dataContext.DbMasterTracks on audioTrack.MasterTrackId equals masterTrack.Id
join masterTrackArtist in dataContext.DbDataLists on masterTrack.ArtistId equals masterTrackArtist.Id
orderby string.Concat(masterTrack.Title, " (", audioTrack.Mix, ") - ", masterTrackArtist.Text)
where (searchOptions.IsInactiveAudioTrackIncluded || audioTrack.IsActive)
&& (searchOptions.IsDeletedAudioTrackIncluded || !audioTrack.IsDeleted)
select new AudioTrack(audioTrack.Id, masterTrack.Id, audioTrack.Isrc, masterTrack.Title, masterTrackArtist.Text, audioTrack.Mix, audioTrack.IsContentExplicit, audioTrack.IsActive, audioTrack.IsDeleted));
}
audioTracks.Sort(a => a.TitleWithMix);
return audioTracks ?? new AudioTracks();
}
UPDATE >>>
Extending my AudioTracks example and working backwards, the GetAudioTracks method is in a project called DataProviders. It is called from a GetAudioTracks method in a DataController class which just adds user feedback and re-try options. That in turn is called by a TracksModel in the Models project which just contains a subsection of methods from the DataController class that relate to the various types of tracks in the application.
Finally, the AudioTracksViewModel in the ViewModels project calls the TracksModel.GetAudioTracks method upon initialisation which happens when the AudioTracksView is loaded by the user. The AudioTracksView has a ListBox on the left containing all of the AudioTrack objects that meet the users search and/or filter selections. The right of the screen has the fields for the selected AudioTrack. Here is what it looks like (if the link seems broken, you can view the image here):
The more transparent fields with an edit Button on the right are read only fields connected to collections. The edit Button opens a dialog to let the user enter multiple items, which are then summarised in the field. All of the objects in the application have similar views of more or less complexity.

Reducing Repositories to Aggregate Roots

I currently have a repository for just about every table in the database and would like to further align myself with DDD by reducing them to aggregate roots only.
Let’s assume that I have the following tables, User and Phone. Each user might have one or more phones. Without the notion of aggregate root I might do something like this:
//assuming I have the userId in session for example and I want to update a phone number
List<Phone> phones = PhoneRepository.GetPhoneNumberByUserId(userId);
phones[0].Number = “911”;
PhoneRepository.Update(phones[0]);
The concept of aggregate roots is easier to understand on paper than in practice. I will never have phone numbers that do not belong to a User, so would it make sense to do away with the PhoneRepository and incorporate phone related methods into the UserRepository? Assuming the answer is yes, I’m going to rewrite the prior code sample.
Am I allowed to have a method on the UserRepository that returns phone numbers? Or should it always return a reference to a User, and then traverse the relationship through the User to get to the phone numbers:
List<Phone> phones = UserRepository.GetPhoneNumbers(userId);
// Or
User user = UserRepository.GetUserWithPhoneNumbers(userId); //this method will join to Phone
Regardless of which way I acquire the phones, assuming I modified one of them, how do I go about updating them? My limited understanding is that objects under the root should be updated through the root, which would steer me towards choice #1 below. Although this will work perfectly well with Entity Framework, this seems extremely un-descriptive, because reading the code I have no idea what I’m actually updating, even though Entity Framework is keeping tab on changed objects within the graph.
UserRepository.Update(user);
// Or
UserRepository.UpdatePhone(phone);
Lastly, assuming I have several lookup tables that are not really tied to anything, such as CountryCodes, ColorsCodes, SomethingElseCodes. I might use them to populate drop downs or for whatever other reason. Are these standalone repositories? Can they be combined into some sort of logical grouping/repository such as CodesRepository? Or is that against best practices.
You are allowed to have any method you want in your repository :) In both of the cases you mention, it makes sense to return the user with phone list populated. Normally user object would not be fully populated with all the sub information (say all addresses, phone numbers) and we may have different methods for getting the user object populated with different kind of information. This is referred to as lazy loading.
User GetUserDetailsWithPhones()
{
// Populate User along with Phones
}
For updating, in this case, the user is being updated, not the phone number itself. Storage model may store the phones in different table and that way you may think that just the phones are being updated but that is not the case if you think from DDD perspective. As far as readability is concerned, while the line
UserRepository.Update(user)
alone doesn't convey what is being updated, the code above it would make it clear what is being updated. Also it would most likely be part of a front end method call that may signifiy what is being updated.
For the lookup tables, and actually even otherwise, it is useful to have GenericRepository and use that. The custom repository can inherit from the GenericRepository.
public class UserRepository : GenericRepository<User>
{
IEnumerable<User> GetUserByCustomCriteria()
{
}
User GetUserDetailsWithPhones()
{
// Populate User along with Phones
}
User GetUserDetailsWithAllSubInfo()
{
// Populate User along with all sub information e.g. phones, addresses etc.
}
}
Search for Generic Repository Entity Framework and you would fine many nice implementation. Use one of those or write your own.
Your example on the Aggregate Root repository is perfectly fine i.e any entity that cannot reasonably exist without dependency on another shouldn't have its own repository (in your case Phone). Without this consideration you can quickly find yourself with an explosion of Repositories in a 1-1 mapping to db tables.
You should look at using the Unit of Work pattern for data changes rather than the repositories themselves as I think they're causing you some confusion around intent when it comes to persisting changes back to the db. In an EF solution the Unit of Work is essentially an interface wrapper around your EF Context.
With regards to your repository for lookup data we simply create a ReferenceDataRepository that becomes responsible for data that doesn't specifically belong to a domain entity (Countries, Colours etc).
If phone makes no sense w/o user, it's an entity (if You care about it's identity) or value object and should always be modified through user and retrieved/updated together.
Think about aggregate roots as context definers - they draw local contexts but are in global context (Your application) themselves.
If You follow domain driven design, repositories are supposed to be 1:1 per aggregate roots.
No excuses.
I bet these are problems You are facing:
technical difficulties - object relation impedance mismatch. You are struggling with persisting whole object graphs with ease and entity framework kind a fails to help.
domain model is data centric (as opposed to behavior centric). because of that - You lose knowledge about object hierarchy (previously mentioned contexts) and magically everything becomes an aggregate root.
I'm not sure how to fix first problem, but I've noticed that fixing second one fixes first good enough. To understand what I mean with behavior centric, give this paper a try.
P.s. Reducing repository to aggregate root makes no sense.
P.p.s. Avoid "CodeRepositories". That leads to data centric -> procedural code.
P.p.p.s Avoid unit of work pattern. Aggregate roots should define transaction boundaries.
This is an old question, but thought worth posting a simple solution.
EF Context is already giving you both Unit of Work (tracks changes) and Repositories (in-memory reference to stuff from DB). Further abstraction is not mandatory.
Remove the DBSet from your context class, as Phone is not an aggregate root.
Use the 'Phones' navigation property on User instead.
static void updateNumber(int userId, string oldNumber, string newNumber)
static void updateNumber(int userId, string oldNumber, string newNumber)
{
using (MyContext uow = new MyContext()) // Unit of Work
{
DbSet<User> repo = uow.Users; // Repository
User user = repo.Find(userId);
Phone oldPhone = user.Phones.Where(x => x.Number.Trim() == oldNumber).SingleOrDefault();
oldPhone.Number = newNumber;
uow.SaveChanges();
}
}
If a Phone entity only makes sense together with an aggregate root User, then I would also think it makes sense that the operation for adding a new Phone record is the responsibility of the User domain object throught a specific method (DDD behavior) and that could make perfectly sense for several reasons, the immidiate reason is we should check the User object exists since the Phone entity depends on it existence and perhaps keep a transaction lock on it while doing more validation checks to ensure no other process have deleted the root aggregate before we are done validating the operation. In other cases with other kinds of root aggregates you might want to aggregate or calculate some value and persist it on column properties of the root aggregate for more efficient processing by other operations later on. Note though I suggest the User domain object have a method that adds the Phone it doesn't mean it should know about the existence of the database or EF, one of the great feature of EM and Hibernate is that they can track changes made to entity classes transparently and that also means adding of new related entities by their navigation collection properties.
Also if you want to use methods that retrieve all phones regardless of the users owning them you could still though it through the User repository you only need one method returns all users as IQueryable then you can map them to get all user phones and do a refined query with that. So you don't even need a PhoneRepository in this case. Beside I would rather use a class with extensions method for IQueryable that I can use anywhere not just from a Repository class if I wanted to abstract queries behind methods.
Just one caveat for being able to delete Phone entities by only using the domain object and not a Phone repository you need to make sure the UserId is part of the Phone primary key or in other words the primary key of a Phone record is a composite key made up of UserId and some other property (I suggest an auto generated identity) in the Phone entity. This makes sense intuively as the Phone record is "owned" by the User record and it's removal from the User navigation collection would equal its complete removal from the database.

Categories