Finally you've got it all. All role definitions, all demand defined and you really want to make all your (for instance) CanView<TEntity> to be easly translated to the NHibernate filtering. Read further and do it in a few minutes!

Service creation

Whether you are using or NHibernate's hbm files finally you can get a Configuration instance, which holds all the mappings. This is the source for creating SessionFactory, the factory of all of your sessions. To allow Themis integrate with NHibernate, the demand service instance must be created in the following way:

// in your application configuration
private void ConfigureDemands(global::NHibernate.Cfg.Configuration cfg)
        .AddRoleDefinition(new ManagerRoleDefinition())
        .AddRoleDefinition(new SupportingManagerRoleDefinition())
        .ConfigureNHibernate(cfg, s => _service = s);
As you can see, the only difference is the service creation method, which uses Configuration object and allows to get an IDemandService via _Action<IDemandService>.

Specific role configuration

To make it work some some work with a base role definition should be done. You should choose, probably one, demands which maps to the filtering of NHibernate entities. To store it in one place, one more time, the BaseRoleDefinition<TRole> is proposed. It consists of two parts: the first maps the ViewDemand, the second - a specific NHibernate demand called EntityDemand<TEntity>. After using it once in your BaseRoleDefinition<TRole>_ class you won't see it again.

public class BaseRoleDefinition<TRole> : RoleDefinition<TRole> where TRole : class
    protected void View<TEntity>(Expression<Func<TEntity, TRole, bool>> expression)
        where TEntity : class
        // mapping standard View<TEntity> demand
        Expression<Func<ViewDemand<TEntity>, TEntity>> accessor = v => v.Entity;
        var result = ExpressionHelper.MapDemandMemberToDemand(expression, accessor);

        // additional mapping of special NHibernate demand, which results in filtering of this entity
        Expression<Func<EntityDemand<TEntity>, TEntity>> nhAccessor = v => v.Entity;
        var nhEntityDemand = ExpressionHelper.MapDemandMemberToDemand(expression, nhAccessor);
After creating this root class, all creating a conditions for querying entities is extremely simple:

public class ManagerRoleDefinition : BaseRoleDefinition<ManagerRole>
    public ManagerRoleDefinition()
        View<RecruitmentMotion>((m, r) => m.ForUnit.Id == r.ManagedUnit.Id); // all motions for manager's unit
        View<RecruitmentMotion>((m, r) => m.Owner.Id == r.ForEmployee.Id); // all motions owned by the employee having this role
This configuration brings to the final step: querying itself! It is done by using an extension method, which creates a scope filtering queries.

using (var scope = _service.ApplyFilters(session, currentUserRoles))
    var count = session.QueryOver<RecruitmentMotion>().RowCountInt64());

One more thing is worth to add. You can simply check the same demand with an instance of IDemandService for a single entity! What Themis.NHibernate does behind the scenes is processing the same expression through two different evaluator factories (IEvaluatorFactory): one for standard delegate creation, second - for NHibernate filtering. For more internal information, view the code.

Last edited Jan 24, 2011 at 7:22 PM by scooletz, version 7


No comments yet.