In my use case we have quite a few tables that store user specific information. Currently, I'm writing out an API that leans heavily on extensions methods in a fluent api fashion. Within these methods I'm accessing the claimPrincipal to limit the set to what this user has rights to. For example, in entity framework (code first) I've got it set up to access a Screens table and a UserSettings table. There is a zero-to-many relationship between them, that is to say, a Screen can have zero-or-more UserSettings. To keep this example simple let's say all users can view all the screens but they should only be able to access the UserSettings assigned to them. What I'm currently doing is setting up functions like the one below to make it easy to filter down the set for this user:
In my case, it would be best if I could just define an expression to limit the result of any dbSet, there by manipulating the users view of the database. There may be 5,000 user settings for any given screen but if Bob is logged into the system Bob should only have access to the 30 he has set. From Bob's perspective the rest shouldn't even exist. What I'm imagining would be something like the following (note: I'm breaking the expression out to make it clearer what it's types would be:
With that all said, on the surface it seems to me that this would be pretty straight forward (just append a where to the object's underlying expression). However, I haven't really looking into the Entity Framework code to see how this would/could be done, nor do I have any experience writing LINQ providers, so I wouldn't be surprised if there is a lot more to this that I haven't considered.
I guess my questions are:
1) Does something already exist that would give me the behavior I'm after?
2) If not, does the approach I laid out seem feasible?
I'd be willing to write this addition and contribute it to the community if that's needed. Like I said before, I don't have any experience writing LINQ providers, so it would probably take a long time.
As a final note, in my search for a solution to this I came across a few examples of others trying to do something similar. In their databases instead of gathering entries for a specific user they would like to gather entries where the column IsDelete = false. I believe the plan I laid out here would satisfy their needs as well. Here are a fewlinks to those cases.
public static IQueriable<UserSetting> ForUser(this IQueriable<UserSettings> settings){
var userId = ClaimsPrincipal.Current.FindFirst( "Id" );
return settings.Where( s=> s.UserId == userId);
}
This works pretty well when querying from context.UserSettings directly, but if working from context.Screens it gets pretty hairy.In my case, it would be best if I could just define an expression to limit the result of any dbSet, there by manipulating the users view of the database. There may be 5,000 user settings for any given screen but if Bob is logged into the system Bob should only have access to the 30 he has set. From Bob's perspective the rest shouldn't even exist. What I'm imagining would be something like the following (note: I'm breaking the expression out to make it clearer what it's types would be:
private Expression<Func<UserSetting, bool>> ForUser( ) {
var userId = ClaimsPrincipal.Current.FindFirst( "Id" );
return s => s.UserId == userId;
}
protected override void OnModelCreating( DbModelBuilder modelBuilder ) {
base.OnModelCreating( modelBuilder );
//Omitted other model setup code
modelBuilder.Entity<UserSetting>( ).Filter( ForUser( ) );
}
The desired end result would be UserSetting whether accessed directly or accessed via navigation property (Screens.First().UserSettings) would only return the rows that have UserId equal to the logged in user. Notice that since the filter is done with an expression it can be modified to reflect whatever user management scheme you have in place. The point of all of this is making this data constraint part of the model so other programmers using this set up don't have to constantly concern themselves with filtering lists for what the user has the right to access. I see it as akin to how navigation properties make it so other programmers don't have to concern themselves with what keys make up the relationships between datasets. With that all said, on the surface it seems to me that this would be pretty straight forward (just append a where to the object's underlying expression). However, I haven't really looking into the Entity Framework code to see how this would/could be done, nor do I have any experience writing LINQ providers, so I wouldn't be surprised if there is a lot more to this that I haven't considered.
I guess my questions are:
1) Does something already exist that would give me the behavior I'm after?
2) If not, does the approach I laid out seem feasible?
I'd be willing to write this addition and contribute it to the community if that's needed. Like I said before, I don't have any experience writing LINQ providers, so it would probably take a long time.
As a final note, in my search for a solution to this I came across a few examples of others trying to do something similar. In their databases instead of gathering entries for a specific user they would like to gather entries where the column IsDelete = false. I believe the plan I laid out here would satisfy their needs as well. Here are a fewlinks to those cases.