Skip to content

Add support for session-scoped interceptors #41

@xhafan

Description

@xhafan

Currently only session-factory-scoped interceptors are supported via overriding BaseNhibernateConfigurator.AdditionalConfiguration:

    protected override void AdditionalConfiguration(Configuration configuration)
    {
        configuration.SetInterceptor(new SomeInterceptor());
    }

Quick idea for the support for session-scoped intereceptors:

public NhibernateUnitOfWork(INhibernateConfigurator configurator, IInterceptor interceptor = null)
{
    _configurator = configurator;
    _interceptor = interceptor;
}
...
        public void BeginTransaction(System.Data.IsolationLevel isolationLevel = System.Data.IsolationLevel.Unspecified)
        {
            _isInTransactionScope = Transaction.Current != null;

            var sessionFactory = _configurator.GetSessionFactory();
            
#if !NET40 && !NET45
            if (_interceptor != null)
            {
                sessionFactory.WithOptions().Interceptor(_interceptor);
            }
            Session = sessionFactory.OpenSession();
#else
            Session = _interceptor != null 
                ? sessionFactory.OpenSession(_interceptor) 
                : sessionFactory.OpenSession();
#endif
            if (_isInTransactionScope) return;

            Session.BeginTransaction(isolationLevel);
        }

Maybe support collection of intereceptors, and use the following CompositeInterceptor:

using System.Collections;
using System.Collections.Generic;
using NHibernate;
using NHibernate.SqlCommand;
using NHibernate.Type;

// taken from https://stackoverflow.com/a/33289268/379279 and modified for nullable 
public class CompositeInterceptor(IEnumerable<IInterceptor> interceptors) : IInterceptor
{
    private readonly IEnumerable<IInterceptor> _interceptors = interceptors.ToList();

    public void AfterTransactionBegin(ITransaction tx)
    {
        foreach (var interceptor in _interceptors)
        {
            interceptor.AfterTransactionBegin(tx);
        }
    }

    public void AfterTransactionCompletion(ITransaction tx)
    {
        foreach (var interceptor in _interceptors)
        {
            interceptor.AfterTransactionCompletion(tx);
        }
    }

    public void BeforeTransactionCompletion(ITransaction tx)
    {
        foreach (var interceptor in _interceptors)
        {
            interceptor.BeforeTransactionCompletion(tx);
        }
    }

    public int[]? FindDirty(
        object entity, 
        object id, 
        object[] currentState, 
        object[] previousState, 
        string[] propertyNames, 
        IType[] types
    )
    {
        var results = _interceptors
            .Select(interceptor => interceptor.FindDirty(entity, id, currentState, previousState, propertyNames, types))
            .Where(result => result != null)
            .SelectMany(x => x)
            .Distinct()
            .ToArray();
        return !results.Any() ? null : results;
    }

    public object? GetEntity(string entityName, object id)
    {
        return _interceptors
            .Select(interceptor => interceptor.GetEntity(entityName, id))
            .FirstOrDefault(result => result != null);
    }

    public string? GetEntityName(object entity)
    {
        return _interceptors
            .Select(interceptor => interceptor.GetEntityName(entity))
            .FirstOrDefault(result => result != null);
    }

    public object? Instantiate(string entityName, object id)
    {
        return _interceptors
            .Select(interceptor => interceptor.Instantiate(entityName, id))
            .FirstOrDefault(result => result != null);
    }

    public bool? IsTransient(object entity)
    {
        return _interceptors
            .Select(interceptor => interceptor.IsTransient(entity))
            .FirstOrDefault(result => result != null);
    }

    public void OnCollectionRecreate(object collection, object key)
    {
        foreach (var interceptor in _interceptors)
        {
            interceptor.OnCollectionRecreate(collection, key);
        }
    }

    public void OnCollectionRemove(object collection, object key)
    {
        foreach (var interceptor in _interceptors)
        {
            interceptor.OnCollectionRemove(collection, key);
        }
    }

    public void OnCollectionUpdate(object collection, object key)
    {
        foreach (var interceptor in _interceptors)
        {
            interceptor.OnCollectionUpdate(collection, key);
        }
    }

    public void OnDelete(
        object entity, 
        object id, 
        object[] state, 
        string[] propertyNames, 
        IType[] types
    )
    {
        foreach (var interceptor in _interceptors)
        {
            interceptor.OnDelete(entity, id, state, propertyNames, types);
        }
    }

    public bool OnFlushDirty(
        object entity, 
        object id, 
        object[] currentState, 
        object[] previousState, 
        string[] propertyNames, 
        IType[] types
    )
    {
        return _interceptors.Any(interceptor => interceptor.OnFlushDirty(entity, id, currentState, previousState, propertyNames, types));
    }

    public bool OnLoad(
        object entity, 
        object id, 
        object[] state, 
        string[] propertyNames,
        IType[] types
    )
    {
        return _interceptors.Any(interceptor => interceptor.OnLoad(entity, id, state, propertyNames, types));
    }

    public SqlString OnPrepareStatement(SqlString sql)
    {
        return _interceptors.Aggregate(sql, (current, interceptor) => interceptor.OnPrepareStatement(current));
    }

    public bool OnSave(
        object entity, 
        object id, 
        object[] state, 
        string[] propertyNames, 
        IType[] types
    )
    {
        return _interceptors.Any(interceptor => interceptor.OnSave(entity, id, state, propertyNames, types));
    }

    public void PostFlush(ICollection entities)
    {
        foreach (var interceptor in _interceptors)
        {
            interceptor.PostFlush(entities);
        }
    }

    public void PreFlush(ICollection entities)
    {
        foreach (var interceptor in _interceptors)
        {
            interceptor.PreFlush(entities);
        }
    }

    public void SetSession(ISession session)
    {
        foreach (var interceptor in _interceptors)
        {
            interceptor.SetSession(session);
        }
    }
}

More info about interceptors:

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions