NHibernate - Lazy-Loading primitive type - c#

I'm using NHibernate to load some objects into my ASP.NET MVC application.
For example, a submission is submitted by a user, and I want to display the username (but only the username) of a user, like this:
<%= Html.Encode(item.User.UserName) %>
When I load a submission using NHibernate, the User is lazy-loaded from the database, which means that the actual SQL query (to load user information) will only be generated and executed when I call the above line of code (which is what I want).
The problem is that the SQL query also selects other information about the user, like it's password, email, etc. This information is obviously not needed and is discarded.
The SQL query looks like this :
SELECT id, username, password, email FROM User WHERE Id = 1;
I conclude that NHibernate only lazy-load references to other objects that are mapped to tables in my database. It does not seem to lazy-load basic, primitive types like strings, ints, etc.
Can I do that? When the above line a code is selected, I would like the SQL query look something like this:
SELECT username FROM User WHERE Id = 1;
Is this possible? How?

Is there a reason you don't want to load the complete object? Except in rare cases, there's no real performance difference.
I can understand not wanting to load the password into memory, although it should be encrypted and probably shouldn't be in your domain model anyway. What I would do in your case is subclass User into two classes, User and UserProfile (containing the password, etc.), so that you only work with the UserProfile object when you are managing the user account.

You'll need to use a resultTransformer to map the query result to the object you want to store it (which I understand is your normal User DTO class but minus all the other fields)
Check this out http://docs.jboss.org/hibernate/stable/core/reference/en/html/querysql.html (its Hibernate, not NHibernate, but it should still apply) specifically section 16.1.5

Related

Authorize data access at database level

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.

User profile service using dynamic

In a system I'm working on there is a core User table. There are also roles designating various user types and application level access.
To keep the user table succinct, there is going to be a number of tables (or possibly just 1 table) holding the extra fields needed for each user type Profile.
Rather than have a number of methods returning each Profile type, would there be any issue with returning an ExpandoObject from the ProfileService? This would allow a simple FetchProfile(foo userType) function.
e.g:
public ExpandoObject FetchProfile(UserType userType)
{
dynamic x = new ExpandoObject();
switch(stuff)
{
case UserType .Type1:
//The ExpandoObject will be pulled from DB using Dapper.Net
return x;
case UserType .Type2:
//The ExpandoObject will be pulled from DB using Dapper.Net
return x;
default:
return null;
}
}
This ProfileService will be used in multiple levels of the framework (n tier.)
Are there any issues with doing this? Or would it be better to use single classes for each profile type and perhaps use generics to pull out the needed Profile class:
public T FetchProfile<T>(UserType userType) where T : IProfileObject ...
The advantage of the ExpandoObject is that the database could be constructed in such a way that new ProfileTypes can be added when the site is live without needing to add extra ProfileType classes.
The solution I arrived at was quite different to my initial ideas, so will document it here for archival purposes.
I built a form manager which allowed the addition of fields and multi-select fields (to be displayed as select lists, check-box lists etc. depending on user configuration.)
I allowed forms to be associated to roles, with fields shared across multiple forms as not to duplicate data.
This allowed me to simply pull out a form based upon role:
var form = formManager.Fetch(User.Username, Role.Name);
And loop through the form elements to generate the fields needed on user profile pages, the form manager being used to save updated data.

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.

Entity per property authorization

I have a ListItem (Sharepoint), but lets think of it as a simple class/entity. Now this entity has a property name Status and other properties.
I need to implement per property/role/status authorization.
Example:
Role = Manager, Field=RequestName, Status=01
Permissions: Read, Update
Role = Manager, Field=RequestName, Status=05
Permissions: Read
As you can see the authorization i basically based on 3 variables: Role, Status, Property
Now, i need in UI to disable/hide some controls based on the fact that a user can see it, or edit it. This can be done easily with a couple of sql tables and some joins.
Given that the entity could have 30-100 Properties, and i need to know whenever to disable/hide controls in UI.
What do you think it would be the best approach:
query the database 30 times and find if the user can read a
certain property
load permissions for all fields given Role and Status, loop in
memory over the collection and get current field permissions.
I'm interested in performance/memory balance. I'm also opened to other authorization algorithms giving that the 3 variables (Role/Status/Property) decide permissions.
Thank you
Keeping 100 small objects in a simple in-memory list is easy and fast. If the property names are unique, you can use an indexed collection, which is even faster.
If they're not being updated constantly there's no reason to query the database.

Overriding SQLMembershipProvider

Is there built in methods into .net framework to do the following:
Get role GUID from user name/user GUID
Get role name from role GUID
So far I have been sending queries to the asp_roles and asp_users tables to obtain that information and I'm wondering if there is a nicer way of doing this?
I have the following methods that I store in the ASPUtilities class:
getRoleGUID(guid userGuid) { LINQ joins }
getRoleGuid(string userName) { LINQ joins }
getRoleName(guid roleGuid) { LINQ joins }
EDIT:
I have just looked into extending SQLMembershipProvider examples.
Few examples completely override the SQLMembershipProvider, but I think what I'm interested is just adding few extra methods to deal with the roles by using LINQ. Is this feasible?
If you extend the SQLMembership provider, it will do the exact same thing, send queries to the database to get that information since the roleID is not stored in session. If you don't want to go through that much trouble, you could do a few things.
Create a custom class with these methods that you can call and will return the ID for you of your role. Essentially, move all of your queries to one location.
Store the role ID in session on login. Call your method you created above once and don't requery everytime. Not 100% of the security risks with this one, however, since you are storing some possibly sensitive role information, the id, in session. Might just be overly cautious though :)

Categories