mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-10-15 19:54:57 +08:00
Implementing NHibernate session hooks
- Configuration events (ISessionConfigurationEvents) and - Interceptors (ISessionInterceptor/AbstractSessionInterceptor). --HG-- branch : 1.x
This commit is contained in:
233
src/Orchard/Data/AbstractSessionInterceptor.cs
Normal file
233
src/Orchard/Data/AbstractSessionInterceptor.cs
Normal file
@@ -0,0 +1,233 @@
|
||||
using System.Collections;
|
||||
using NHibernate;
|
||||
using NHibernate.SqlCommand;
|
||||
using NHibernate.Type;
|
||||
|
||||
namespace Orchard.Data {
|
||||
/// <summary>
|
||||
/// Abstract implementation of a per-session NHibernate session interceptor.
|
||||
/// </summary>
|
||||
public abstract class AbstractSessionInterceptor : ISessionInterceptor {
|
||||
/// <summary>
|
||||
/// Called just before an object is initialized
|
||||
/// </summary>
|
||||
/// <param name="entity"/><param name="id"/><param name="propertyNames"/><param name="state"/><param name="types"/>
|
||||
/// <remarks>
|
||||
/// The interceptor may change the <c>state</c>, which will be propagated to the persistent
|
||||
/// object. Note that when this method is called, <c>entity</c> will be an empty
|
||||
/// uninitialized instance of the class.
|
||||
/// </remarks>
|
||||
/// <returns>
|
||||
/// <see langword="true"/> if the user modified the <c>state</c> in any way
|
||||
/// </returns>
|
||||
public virtual bool OnLoad(object entity, object id, object[] state, string[] propertyNames, IType[] types) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when an object is detected to be dirty, during a flush.
|
||||
/// </summary>
|
||||
/// <param name="currentState"/><param name="entity"/><param name="id"/><param name="previousState"/><param name="propertyNames"/><param name="types"/>
|
||||
/// <remarks>
|
||||
/// The interceptor may modify the detected <c>currentState</c>, which will be propagated to
|
||||
/// both the database and the persistent object. Note that all flushes end in an actual
|
||||
/// synchronization with the database, in which as the new <c>currentState</c> will be propagated
|
||||
/// to the object, but not necessarily (immediately) to the database. It is strongly recommended
|
||||
/// that the interceptor <b>not</b> modify the <c>previousState</c>.
|
||||
/// </remarks>
|
||||
/// <returns>
|
||||
/// <see langword="true"/> if the user modified the <c>currentState</c> in any way
|
||||
/// </returns>
|
||||
public virtual bool OnFlushDirty(object entity, object id, object[] currentState, object[] previousState, string[] propertyNames, IType[] types) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called before an object is saved
|
||||
/// </summary>
|
||||
/// <param name="entity"/><param name="id"/><param name="propertyNames"/><param name="state"/><param name="types"/>
|
||||
/// <remarks>
|
||||
/// The interceptor may modify the <c>state</c>, which will be used for the SQL <c>INSERT</c>
|
||||
/// and propagated to the persistent object
|
||||
/// </remarks>
|
||||
/// <returns>
|
||||
/// <see langword="true"/> if the user modified the <c>state</c> in any way
|
||||
/// </returns>
|
||||
public virtual bool OnSave(object entity, object id, object[] state, string[] propertyNames, IType[] types) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called before an object is deleted
|
||||
/// </summary>
|
||||
/// <param name="entity"/><param name="id"/><param name="propertyNames"/><param name="state"/><param name="types"/>
|
||||
/// <remarks>
|
||||
/// It is not recommended that the interceptor modify the <c>state</c>.
|
||||
/// </remarks>
|
||||
public virtual void OnDelete(object entity, object id, object[] state, string[] propertyNames, IType[] types) {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called before a collection is (re)created.
|
||||
/// </summary>
|
||||
public virtual void OnCollectionRecreate(object collection, object key) {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called before a collection is deleted.
|
||||
/// </summary>
|
||||
public virtual void OnCollectionRemove(object collection, object key) {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called before a collection is updated.
|
||||
/// </summary>
|
||||
public virtual void OnCollectionUpdate(object collection, object key) {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called before a flush
|
||||
/// </summary>
|
||||
/// <param name="entities">The entities</param>
|
||||
public virtual void PreFlush(ICollection entities) {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called after a flush that actually ends in execution of the SQL statements required to
|
||||
/// synchronize in-memory state with the database.
|
||||
/// </summary>
|
||||
/// <param name="entities">The entitites</param>
|
||||
public virtual void PostFlush(ICollection entities) {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when a transient entity is passed to <c>SaveOrUpdate</c>.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The return value determines if the object is saved
|
||||
/// <list>
|
||||
/// <item>
|
||||
/// <see langword="true"/> - the entity is passed to <c>Save()</c>, resulting in an <c>INSERT</c>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <see langword="false"/> - the entity is passed to <c>Update()</c>, resulting in an <c>UPDATE</c>
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <see langword="null"/> - Hibernate uses the <c>unsaved-value</c> mapping to determine if the object is unsaved
|
||||
/// </item>
|
||||
/// </list>
|
||||
/// </remarks>
|
||||
/// <param name="entity">A transient entity</param>
|
||||
/// <returns>
|
||||
/// Boolean or <see langword="null"/> to choose default behaviour
|
||||
/// </returns>
|
||||
public virtual bool? IsTransient(object entity) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called from <c>Flush()</c>. The return value determines whether the entity is updated
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <list>
|
||||
/// <item>
|
||||
/// an array of property indicies - the entity is dirty
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// an empty array - the entity is not dirty
|
||||
/// </item>
|
||||
/// <item>
|
||||
/// <see langword="null"/> - use Hibernate's default dirty-checking algorithm
|
||||
/// </item>
|
||||
/// </list>
|
||||
/// </remarks>
|
||||
/// <param name="entity">A persistent entity</param><param name="currentState"/><param name="id"/><param name="previousState"/><param name="propertyNames"/><param name="types"/>
|
||||
/// <returns>
|
||||
/// An array of dirty property indicies or <see langword="null"/> to choose default behavior
|
||||
/// </returns>
|
||||
public virtual int[] FindDirty(object entity, object id, object[] currentState, object[] previousState, string[] propertyNames, IType[] types) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Instantiate the entity class. Return <see langword="null"/> to indicate that Hibernate should use the default
|
||||
/// constructor of the class
|
||||
/// </summary>
|
||||
/// <param name="entityName">the name of the entity </param><param name="entityMode">The type of entity instance to be returned. </param><param name="id">the identifier of the new instance </param>
|
||||
/// <returns>
|
||||
/// An instance of the class, or <see langword="null"/> to choose default behaviour
|
||||
/// </returns>
|
||||
/// <remarks>
|
||||
/// The identifier property of the returned instance
|
||||
/// should be initialized with the given identifier.
|
||||
/// </remarks>
|
||||
public virtual object Instantiate(string entityName, EntityMode entityMode, object id) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the entity name for a persistent or transient instance
|
||||
/// </summary>
|
||||
/// <param name="entity">an entity instance </param>
|
||||
/// <returns>
|
||||
/// the name of the entity
|
||||
/// </returns>
|
||||
public virtual string GetEntityName(object entity) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a fully loaded entity instance that is cached externally
|
||||
/// </summary>
|
||||
/// <param name="entityName">the name of the entity </param><param name="id">the instance identifier </param>
|
||||
/// <returns>
|
||||
/// a fully initialized entity
|
||||
/// </returns>
|
||||
public virtual object GetEntity(string entityName, object id)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when a NHibernate transaction is begun via the NHibernate <see cref="T:NHibernate.ITransaction"/>
|
||||
/// API. Will not be called if transactions are being controlled via some other mechanism.
|
||||
/// </summary>
|
||||
public virtual void AfterTransactionBegin(ITransaction tx) {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called before a transaction is committed (but not before rollback).
|
||||
/// </summary>
|
||||
public virtual void BeforeTransactionCompletion(ITransaction tx) {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called after a transaction is committed or rolled back.
|
||||
/// </summary>
|
||||
public virtual void AfterTransactionCompletion(ITransaction tx) {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when sql string is being prepared.
|
||||
/// </summary>
|
||||
/// <param name="sql">sql to be prepared </param>
|
||||
/// <returns>
|
||||
/// original or modified sql
|
||||
/// </returns>
|
||||
public virtual SqlString OnPrepareStatement(SqlString sql) {
|
||||
return sql;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when a session-scoped (and <b>only</b> session scoped) interceptor is attached
|
||||
/// to a session
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// session-scoped-interceptor is an instance of the interceptor used only for one session.
|
||||
/// The use of singleton-interceptor may cause problems in multi-thread scenario.
|
||||
/// </remarks>
|
||||
/// <seealso cref="M:NHibernate.ISessionFactory.OpenSession(NHibernate.IInterceptor)"/><seealso cref="M:NHibernate.ISessionFactory.OpenSession(System.Data.IDbConnection,NHibernate.IInterceptor)"/>
|
||||
public virtual void SetSession(ISession session) {
|
||||
}
|
||||
}
|
||||
}
|
50
src/Orchard/Data/ISessionConfigurationEvents.cs
Normal file
50
src/Orchard/Data/ISessionConfigurationEvents.cs
Normal file
@@ -0,0 +1,50 @@
|
||||
using FluentNHibernate.Automapping;
|
||||
using FluentNHibernate.Cfg;
|
||||
using NHibernate.Cfg;
|
||||
using Orchard.Utility;
|
||||
|
||||
namespace Orchard.Data {
|
||||
/// <summary>
|
||||
/// Allows hooking into NHibernate session configuration pipeline.
|
||||
/// </summary>
|
||||
public interface ISessionConfigurationEvents : ISingletonDependency {
|
||||
/// <summary>
|
||||
/// Called when an empty fluent configuration object has been created,
|
||||
/// before applying any default Orchard config settings (alterations, conventions etc.).
|
||||
/// </summary>
|
||||
/// <param name="cfg">Empty fluent NH configuration object.</param>
|
||||
/// <param name="defaultModel">Default persistence model that is about to be used.</param>
|
||||
void Created(FluentConfiguration cfg, AutoPersistenceModel defaultModel);
|
||||
|
||||
/// <summary>
|
||||
/// Called when fluent configuration has been prepared but not yet built.
|
||||
/// </summary>
|
||||
/// <param name="cfg">Prepared fluent NH configuration object.</param>
|
||||
void Prepared(FluentConfiguration cfg);
|
||||
|
||||
/// <summary>
|
||||
/// Called when raw NHibernate configuration is being built, after applying all customizations.
|
||||
/// Allows applying final alterations to the raw NH configuration.
|
||||
/// </summary>
|
||||
/// <param name="cfg">Raw NH configuration object being processed.</param>
|
||||
void Building(Configuration cfg);
|
||||
|
||||
/// <summary>
|
||||
/// Called when NHibernate configuration has been built or read from cache storage (mappings.bin file by default).
|
||||
/// </summary>
|
||||
/// <param name="cfg">Final, raw NH configuration object.</param>
|
||||
void Finished(Configuration cfg);
|
||||
|
||||
/// <summary>
|
||||
/// Called when configuration hash is being computed. If hash changes, configuration will be rebuilt and stored in mappings.bin.
|
||||
/// This method allows to alter the default hash to take into account custom configuration changes.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// It's a developer responsibility to make sure hash is correctly updated when config needs to be rebuilt.
|
||||
/// Otherwise the cached configuration (mappings.bin file) will be used as long as default Orchard configuration
|
||||
/// is unchanged or until the file is manually removed.
|
||||
/// </remarks>
|
||||
/// <param name="hash">Current hash object</param>
|
||||
void ComputingHash(Hash hash);
|
||||
}
|
||||
}
|
9
src/Orchard/Data/ISessionInterceptor.cs
Normal file
9
src/Orchard/Data/ISessionInterceptor.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using NHibernate;
|
||||
|
||||
namespace Orchard.Data {
|
||||
/// <summary>
|
||||
/// Describes an NHibernate session interceptor, instantiated per-session.
|
||||
/// </summary>
|
||||
public interface ISessionInterceptor : IInterceptor, IDependency {
|
||||
}
|
||||
}
|
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Configuration;
|
||||
using System.Linq;
|
||||
using FluentNHibernate;
|
||||
using FluentNHibernate.Automapping;
|
||||
@@ -9,7 +10,6 @@ using FluentNHibernate.Cfg.Db;
|
||||
using FluentNHibernate.Conventions.Helpers;
|
||||
using FluentNHibernate.Diagnostics;
|
||||
using NHibernate;
|
||||
using NHibernate.Cfg;
|
||||
using NHibernate.Engine;
|
||||
using NHibernate.Event;
|
||||
using NHibernate.Event.Default;
|
||||
@@ -17,6 +17,8 @@ using NHibernate.Persister.Entity;
|
||||
using Orchard.ContentManagement.Records;
|
||||
using Orchard.Data.Conventions;
|
||||
using Orchard.Environment.ShellBuilders.Models;
|
||||
using Orchard.Logging;
|
||||
using Configuration = NHibernate.Cfg.Configuration;
|
||||
|
||||
namespace Orchard.Data.Providers {
|
||||
[Serializable]
|
||||
@@ -24,16 +26,30 @@ namespace Orchard.Data.Providers {
|
||||
|
||||
public abstract IPersistenceConfigurer GetPersistenceConfigurer(bool createDatabase);
|
||||
|
||||
protected AbstractDataServicesProvider() {
|
||||
Logger = NullLogger.Instance;
|
||||
}
|
||||
|
||||
public ILogger Logger { get; set; }
|
||||
|
||||
public Configuration BuildConfiguration(SessionFactoryParameters parameters) {
|
||||
var database = GetPersistenceConfigurer(parameters.CreateDatabase);
|
||||
var persistenceModel = CreatePersistenceModel(parameters.RecordDescriptors.ToList());
|
||||
|
||||
return Fluently.Configure()
|
||||
.Database(database)
|
||||
.Mappings(m => m.AutoMappings.Add(persistenceModel))
|
||||
.ExposeConfiguration(cfg => cfg.EventListeners.LoadEventListeners = new ILoadEventListener[] { new OrchardLoadEventListener() })
|
||||
.BuildConfiguration()
|
||||
;
|
||||
var config = Fluently.Configure();
|
||||
|
||||
parameters.Configurers.Invoke(c => c.Created(config, persistenceModel), Logger);
|
||||
|
||||
config = config.Database(database)
|
||||
.Mappings(m => m.AutoMappings.Add(persistenceModel))
|
||||
.ExposeConfiguration(cfg => {
|
||||
cfg.EventListeners.LoadEventListeners = new ILoadEventListener[] {new OrchardLoadEventListener()};
|
||||
parameters.Configurers.Invoke(c => c.Building(cfg), Logger);
|
||||
});
|
||||
|
||||
parameters.Configurers.Invoke(c => c.Prepared(config), Logger);
|
||||
|
||||
return config.BuildConfiguration();
|
||||
}
|
||||
|
||||
public static AutoPersistenceModel CreatePersistenceModel(ICollection<RecordBlueprint> recordDescriptors) {
|
||||
|
@@ -1,8 +1,13 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Orchard.Environment.ShellBuilders.Models;
|
||||
|
||||
namespace Orchard.Data.Providers {
|
||||
public class SessionFactoryParameters : DataServiceParameters {
|
||||
public SessionFactoryParameters() {
|
||||
Configurers = Enumerable.Empty<ISessionConfigurationEvents>();
|
||||
}
|
||||
public IEnumerable<ISessionConfigurationEvents> Configurers { get; set; }
|
||||
public IEnumerable<RecordBlueprint> RecordDescriptors { get; set; }
|
||||
public bool CreateDatabase { get; set; }
|
||||
}
|
||||
|
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Serialization;
|
||||
@@ -17,13 +18,15 @@ namespace Orchard.Data {
|
||||
private readonly ShellBlueprint _shellBlueprint;
|
||||
private readonly IAppDataFolder _appDataFolder;
|
||||
private readonly IHostEnvironment _hostEnvironment;
|
||||
private readonly IEnumerable<ISessionConfigurationEvents> _configurers;
|
||||
private ConfigurationCache _currentConfig;
|
||||
|
||||
public SessionConfigurationCache(ShellSettings shellSettings, ShellBlueprint shellBlueprint, IAppDataFolder appDataFolder, IHostEnvironment hostEnvironment) {
|
||||
public SessionConfigurationCache(ShellSettings shellSettings, ShellBlueprint shellBlueprint, IAppDataFolder appDataFolder, IHostEnvironment hostEnvironment, IEnumerable<ISessionConfigurationEvents> configurers) {
|
||||
_shellSettings = shellSettings;
|
||||
_shellBlueprint = shellBlueprint;
|
||||
_appDataFolder = appDataFolder;
|
||||
_hostEnvironment = hostEnvironment;
|
||||
_configurers = configurers;
|
||||
_currentConfig = null;
|
||||
|
||||
Logger = NullLogger.Instance;
|
||||
@@ -161,6 +164,8 @@ namespace Orchard.Data {
|
||||
}
|
||||
}
|
||||
|
||||
_configurers.Invoke(c => c.ComputingHash(hash), Logger);
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
|
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using NHibernate;
|
||||
using NHibernate.Cfg;
|
||||
using Orchard.Data.Providers;
|
||||
@@ -22,6 +23,7 @@ namespace Orchard.Data {
|
||||
private readonly ShellBlueprint _shellBlueprint;
|
||||
private readonly IHostEnvironment _hostEnvironment;
|
||||
private readonly IDatabaseCacheConfiguration _cacheConfiguration;
|
||||
private readonly Func<IEnumerable<ISessionConfigurationEvents>> _configurers;
|
||||
private readonly IDataServicesProviderFactory _dataServicesProviderFactory;
|
||||
private readonly IAppDataFolder _appDataFolder;
|
||||
private readonly ISessionConfigurationCache _sessionConfigurationCache;
|
||||
@@ -36,7 +38,8 @@ namespace Orchard.Data {
|
||||
IAppDataFolder appDataFolder,
|
||||
ISessionConfigurationCache sessionConfigurationCache,
|
||||
IHostEnvironment hostEnvironment,
|
||||
IDatabaseCacheConfiguration cacheConfiguration) {
|
||||
IDatabaseCacheConfiguration cacheConfiguration,
|
||||
Func<IEnumerable<ISessionConfigurationEvents>> configurers) {
|
||||
_shellSettings = shellSettings;
|
||||
_shellBlueprint = shellBlueprint;
|
||||
_dataServicesProviderFactory = dataServicesProviderFactory;
|
||||
@@ -44,6 +47,7 @@ namespace Orchard.Data {
|
||||
_sessionConfigurationCache = sessionConfigurationCache;
|
||||
_hostEnvironment = hostEnvironment;
|
||||
_cacheConfiguration = cacheConfiguration;
|
||||
_configurers = configurers;
|
||||
|
||||
T = NullLocalizer.Instance;
|
||||
Logger = NullLogger.Instance;
|
||||
@@ -117,6 +121,8 @@ namespace Orchard.Data {
|
||||
}
|
||||
#endregion
|
||||
|
||||
parameters.Configurers.Invoke(c => c.Finished(config), Logger);
|
||||
|
||||
Logger.Debug("Done Building configuration");
|
||||
return config;
|
||||
}
|
||||
@@ -128,6 +134,7 @@ namespace Orchard.Data {
|
||||
var shellFolder = _appDataFolder.MapPath(shellPath);
|
||||
|
||||
return new SessionFactoryParameters {
|
||||
Configurers = _configurers(),
|
||||
Provider = _shellSettings.DataProvider,
|
||||
DataFolder = shellFolder,
|
||||
ConnectionString = _shellSettings.DataConnectionString,
|
||||
|
@@ -1,20 +1,28 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using NHibernate;
|
||||
using NHibernate.SqlCommand;
|
||||
using NHibernate.Type;
|
||||
using Orchard.Exceptions;
|
||||
using Orchard.Logging;
|
||||
using Orchard.Security;
|
||||
|
||||
namespace Orchard.Data {
|
||||
public class SessionLocator : ISessionLocator, ITransactionManager, IDisposable {
|
||||
private readonly ISessionFactoryHolder _sessionFactoryHolder;
|
||||
private readonly IEnumerable<ISessionInterceptor> _interceptors;
|
||||
private ISession _session;
|
||||
private ITransaction _transaction;
|
||||
private bool _cancelled;
|
||||
|
||||
public SessionLocator(ISessionFactoryHolder sessionFactoryHolder) {
|
||||
public SessionLocator(
|
||||
ISessionFactoryHolder sessionFactoryHolder,
|
||||
IEnumerable<ISessionInterceptor> interceptors) {
|
||||
_sessionFactoryHolder = sessionFactoryHolder;
|
||||
_interceptors = interceptors;
|
||||
Logger = NullLogger.Instance;
|
||||
}
|
||||
|
||||
@@ -96,77 +104,142 @@ namespace Orchard.Data {
|
||||
|
||||
var sessionFactory = _sessionFactoryHolder.GetSessionFactory();
|
||||
Logger.Information("Opening database session");
|
||||
_session = sessionFactory.OpenSession(new SessionInterceptor());
|
||||
_session = sessionFactory.OpenSession(new OrchardSessionInterceptor(_interceptors.ToArray(), Logger));
|
||||
}
|
||||
|
||||
class SessionInterceptor : IInterceptor {
|
||||
class OrchardSessionInterceptor : IInterceptor {
|
||||
private readonly ISessionInterceptor[] _interceptors;
|
||||
private readonly ILogger _logger;
|
||||
private ISession _session;
|
||||
|
||||
public OrchardSessionInterceptor(ISessionInterceptor[] interceptors, ILogger logger) {
|
||||
_interceptors = interceptors;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
bool IInterceptor.OnLoad(object entity, object id, object[] state, string[] propertyNames, IType[] types) {
|
||||
return false;
|
||||
if (_interceptors.Length == 0) return false;
|
||||
return _interceptors.Invoke(i => i.OnLoad(entity, id, state, propertyNames, types), _logger).ToList().Any(r => r);
|
||||
}
|
||||
|
||||
bool IInterceptor.OnFlushDirty(object entity, object id, object[] currentState, object[] previousState, string[] propertyNames, IType[] types) {
|
||||
return false;
|
||||
if (_interceptors.Length == 0) return false;
|
||||
return _interceptors.Invoke(i => i.OnFlushDirty(entity, id, currentState, previousState, propertyNames, types), _logger).ToList().Any(r => r);
|
||||
}
|
||||
|
||||
bool IInterceptor.OnSave(object entity, object id, object[] state, string[] propertyNames, IType[] types) {
|
||||
return false;
|
||||
if (_interceptors.Length == 0) return false;
|
||||
return _interceptors.Invoke(i => i.OnSave(entity, id, state, propertyNames, types), _logger).ToList().Any(r => r);
|
||||
}
|
||||
|
||||
void IInterceptor.OnDelete(object entity, object id, object[] state, string[] propertyNames, IType[] types) {
|
||||
if (_interceptors.Length == 0) return;
|
||||
_interceptors.Invoke(i => i.OnDelete(entity, id, state, propertyNames, types), _logger);
|
||||
}
|
||||
|
||||
void IInterceptor.OnCollectionRecreate(object collection, object key) {
|
||||
if (_interceptors.Length == 0) return;
|
||||
_interceptors.Invoke(i => i.OnCollectionRecreate(collection, key), _logger);
|
||||
}
|
||||
|
||||
void IInterceptor.OnCollectionRemove(object collection, object key) {
|
||||
if (_interceptors.Length == 0) return;
|
||||
_interceptors.Invoke(i => i.OnCollectionRemove(collection, key), _logger);
|
||||
}
|
||||
|
||||
void IInterceptor.OnCollectionUpdate(object collection, object key) {
|
||||
if (_interceptors.Length == 0) return;
|
||||
_interceptors.Invoke(i => i.OnCollectionUpdate(collection, key), _logger);
|
||||
}
|
||||
|
||||
void IInterceptor.PreFlush(ICollection entities) {
|
||||
if (_interceptors.Length == 0) return;
|
||||
_interceptors.Invoke(i => i.PreFlush(entities), _logger);
|
||||
}
|
||||
|
||||
void IInterceptor.PostFlush(ICollection entities) {
|
||||
if (_interceptors.Length == 0) return;
|
||||
_interceptors.Invoke(i => i.PostFlush(entities), _logger);
|
||||
}
|
||||
|
||||
bool? IInterceptor.IsTransient(object entity) {
|
||||
return null;
|
||||
if (_interceptors.Length == 0) return null;
|
||||
return _interceptors.Invoke(i => i.IsTransient(entity), _logger).ToList().FirstOrDefault(c => c.HasValue && c.Value);
|
||||
}
|
||||
|
||||
int[] IInterceptor.FindDirty(object entity, object id, object[] currentState, object[] previousState, string[] propertyNames, IType[] types) {
|
||||
return null;
|
||||
if (_interceptors.Length == 0) return null;
|
||||
var retVal = _interceptors.Invoke(i => i.FindDirty(entity, id, currentState, previousState, propertyNames, types), _logger)
|
||||
.Where(r => r != null)
|
||||
.SelectMany(r => r)
|
||||
.ToArray();
|
||||
|
||||
return retVal.Length == 0 ? null : retVal;
|
||||
}
|
||||
|
||||
object IInterceptor.Instantiate(string entityName, EntityMode entityMode, object id) {
|
||||
return null;
|
||||
if (_interceptors.Length == 0) return null;
|
||||
return _interceptors.Invoke(i => i.Instantiate(entityName, entityMode, id), _logger).FirstOrDefault(r => r != null);
|
||||
}
|
||||
|
||||
string IInterceptor.GetEntityName(object entity) {
|
||||
return null;
|
||||
if (_interceptors.Length == 0) return null;
|
||||
return _interceptors.Invoke(i => i.GetEntityName(entity), _logger).FirstOrDefault(r => r != null);
|
||||
}
|
||||
|
||||
object IInterceptor.GetEntity(string entityName, object id) {
|
||||
return null;
|
||||
if (_interceptors.Length == 0) return null;
|
||||
return _interceptors.Invoke(i => i.GetEntity(entityName, id), _logger).FirstOrDefault(r => r != null);
|
||||
}
|
||||
|
||||
void IInterceptor.AfterTransactionBegin(ITransaction tx) {
|
||||
if (_interceptors.Length == 0) return;
|
||||
_interceptors.Invoke(i => i.AfterTransactionBegin(tx), _logger);
|
||||
}
|
||||
|
||||
void IInterceptor.BeforeTransactionCompletion(ITransaction tx) {
|
||||
if (_interceptors.Length == 0) return;
|
||||
_interceptors.Invoke(i => i.BeforeTransactionCompletion(tx), _logger);
|
||||
}
|
||||
|
||||
void IInterceptor.AfterTransactionCompletion(ITransaction tx) {
|
||||
if (_interceptors.Length == 0) return;
|
||||
_interceptors.Invoke(i => i.AfterTransactionCompletion(tx), _logger);
|
||||
}
|
||||
|
||||
SqlString IInterceptor.OnPrepareStatement(SqlString sql) {
|
||||
return sql;
|
||||
if (_interceptors.Length == 0) return sql;
|
||||
|
||||
// Cannot use Invoke, as we need to pass previous result to the next interceptor
|
||||
return _interceptors.Aggregate(sql, (current, i) => {
|
||||
try {
|
||||
return i.OnPrepareStatement(current);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
if (IsLogged(ex)) {
|
||||
_logger.Error(ex, "{2} thrown from ISessionInterceptor by {0}",
|
||||
i.GetType().FullName,
|
||||
ex.GetType().Name);
|
||||
}
|
||||
|
||||
if (ex.IsFatal()) {
|
||||
throw;
|
||||
}
|
||||
|
||||
return current;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void IInterceptor.SetSession(ISession session) {
|
||||
_session = session;
|
||||
|
||||
if (_interceptors.Length == 0) return;
|
||||
_interceptors.Invoke(i => i.SetSession(session), _logger);
|
||||
}
|
||||
|
||||
private static bool IsLogged(Exception ex) {
|
||||
return ex is OrchardSecurityException || !ex.IsFatal();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -170,6 +170,7 @@
|
||||
<Compile Include="ContentManagement\MetaData\Services\ISettingsFormatter.cs" />
|
||||
<Compile Include="ContentManagement\QueryHints.cs" />
|
||||
<Compile Include="ContentManagement\Utilities\ComputedField.cs" />
|
||||
<Compile Include="Data\AbstractSessionInterceptor.cs" />
|
||||
<Compile Include="Data\Bags\SArray.cs" />
|
||||
<Compile Include="Data\FetchRequest.cs" />
|
||||
<Compile Include="DisplayManagement\Arguments.cs" />
|
||||
@@ -186,6 +187,8 @@
|
||||
<Compile Include="Data\IDatabaseCacheConfiguration.cs" />
|
||||
<Compile Include="Data\Migration\AutomaticDataMigrations.cs" />
|
||||
<Compile Include="Data\Migration\Interpreters\SqlCeCommandInterpreter.cs" />
|
||||
<Compile Include="Data\ISessionConfigurationEvents.cs" />
|
||||
<Compile Include="Data\ISessionInterceptor.cs" />
|
||||
<Compile Include="DisplayManagement\Descriptors\PlacementInfo.cs" />
|
||||
<Compile Include="DisplayManagement\Descriptors\ResourceBindingStrategy\StylesheetBindingStrategy.cs" />
|
||||
<Compile Include="DisplayManagement\Descriptors\ShapeDescriptor.cs" />
|
||||
|
Reference in New Issue
Block a user