Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for session-scoped interceptors #41

Open
xhafan opened this issue Jan 3, 2024 · 0 comments
Open

Add support for session-scoped interceptors #41

xhafan opened this issue Jan 3, 2024 · 0 comments
Labels
enhancement New feature or request

Comments

@xhafan
Copy link
Owner

xhafan commented Jan 3, 2024

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:

@xhafan xhafan added the enhancement New feature or request label Jan 3, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

1 participant