Querying Is A Business Concern: Sample

In a recent post, I said that I believe that querying is a business concern. I gave an example there, but I think that this one is a more appropriate for the point that I am trying to make.

The model is very simple, and is shown below. Please do not mention AzMan, I already know about it.

Given a user, I need to find out whatever is has a particular operation with a particular permission. The permissions enum is a bit flag enumeration, with the usual suspects in increasing order (1,2,4,8).

(Image from clipboard).png

The really simple thing to would simply move across the object graph, something like:

bool hasPermission =

       user.Groups.Exists(grp => grp.Roles

                     .Exists(role => role.Operations

                           .Exists(op => op.Permissions == requiredPermission)));

I use Linq because it looks cool, here. This is simple, but it is also extremely ineffiecnt. It is much better to let the database do what it is good at, and run a query to get the result back.

Here is my first attempt.

select    op from Operation op, Group group

where     op.Name = :operationName

and       (op.Permissions & :requiredPermission) != 0

and       :user in elements(group.Users)

and       op.Role in elements(group.Roles)

It resulted in pretty good SQL, but the op.Role in elements(group.Roles) bothered me. That is easy to write, but in SQL that translated to:

and permissions1_.Role in (select role1_.Id from

     Roles role1 where role1.Group = grp1_.Id)

Looking into the execution plan, I thought that I could do better, and I re-wrote the query to be a bit

select   op from Group group

join     group.Users user

join     group.Roles role

join     role.Operations op

where    user = :user

and      (op.Permissions & :requiredPermission) != 0

and      op.Name = :operationName

This turned out to be much more efficent (two clustered index scans less).

Anyway, I am letting the technology sway me away from a architectual discussion. This query is sitting on an AuthorizationService, and I consider it a 100% business logic.

Print | posted on Monday, March 12, 2007 11:45 PM

Feedback


Gravatar

# re: Querying Is A Business Concern: Sample 3/13/2007 2:01 AM SteveG

Ayende,

Although it might be inefficient, is there a tradeoff here depending on the situation?

I wonder as well, does this Linq query get cached ?

I do however agree with your comments, this is very much business logic!


Gravatar

# re: Querying Is A Business Concern: Sample 3/13/2007 3:52 AM Derick Bailey

shouldn't the "process" of obtaining the permissions be the business logic, but the actual query mechanics be service logic? I believe there is a distinct difference between the two, although the implementation may join them via interface vs. implementation.


Gravatar

# re: Querying Is A Business Concern: Sample 3/13/2007 6:41 AM Richard LOPES

I very much agree with the architecture proposed by Derick.


Gravatar

# re: Querying Is A Business Concern: Sample 3/13/2007 7:10 AM Ayende Rahien

@SteveG,
Just the first query is using Linq, the other two are HQL queries.
There are no real trade offs between the two queries, except for efficiencies.

Yes, you can cache this query


Gravatar

# re: Querying Is A Business Concern: Sample 3/13/2007 7:11 AM Ayende Rahien

@Derick,
Can you define what is a query mechanics in this case?

The code that I am using is:

ICollection<Permission> permissions = Repository<Permission>.FindAll("query", parameters);
return permissions.Count != 0


Gravatar

# re: Querying Is A Business Concern: Sample 3/13/2007 3:20 PM Derick Bailey

Ayende,

The code that you post in your comment is what I would consider to be the mechanics - the service portion of the call - and should be hidden behind an interface. My basic reasoning for making this statement is encapsulation - to allow the mechanics of the query to change, without the semantics of the call changing.

This becomes even more important in unit testing. If I am going to test the CRUD permissions of a Controller for a screen, I need to be able to mock the CRUD call to return an expected result, without having the real permission store set up and connected.

public interface IPermissionService
{

public ICollection<Permission> GetPermissions();

}


public class PermissionService: IPermissionService
{

public ICollection<Permission> GetPermissions()
{
return Repository<Permission>.FindAll("query", parameters);
}

}


Gravatar

# re: Querying Is A Business Concern: Sample 3/13/2007 3:33 PM Ayende Rahien

Did notice that the query is in the authorization service?
The only logic in the IsAllowed() method is in the query, so to test that I need a DB anyway.
If I don't want that, I can mock the authorization service directly.


Gravatar

# Is Querying a business concern or a service concern? 3/13/2007 6:24 PM Dim Blog As New ThoughtStream(me)

Ayende Makes The Statement that Querying Is A Business Concern. I have often made this same statement...


Gravatar

# re: Querying Is A Business Concern: Sample 3/14/2007 1:30 AM Derick Bailey

This turned out to be a semantic misunderstanding on my part, not a design or implementation difference. My appologies for the misunderstanding.


Gravatar

# re: Querying Is A Business Concern: Sample 3/14/2007 1:32 AM Ayende Rahien

No problem.
I am glad to know that we agree with each other.

Comments have been closed on this topic.