obase社区Obase开发者QQ群:962698871
obase

欢迎查阅
OBASE帮助文档

我们之前在开始使用的再攀高峰中已经演示过如何定义映射模块,继承IMappingModule接口后在Init方法中订阅要处理的映射管道事件即可。这里我们讲一下这些映射管道的具体事件是在何时被触发的,以及他们触发时会一并抛出的事件数据。

/// <summary>
///     “保存”管道接口。
/// </summary>
public interface ISavingPipeline
{
    /// <summary>
    ///     为PreExecuteSql事件附加或移除事件处理程序。
    /// </summary>
    event EventHandler<PreExecuteCommandEventArgs> PreExecuteCommand;

    /// <summary>
    ///     为PostExecuteSql事件附加或移除事件处理程序。
    /// </summary>
    event EventHandler<PostExecuteCommandEventArgs> PostExecuteCommand;

    /// <summary>
    ///     为BeginSaving事件附加或移除事件处理程序。
    /// </summary>
    event EventHandler BeginSaving;

    /// <summary>
    ///     为PostGenerateQueue事件附加或移除事件处理程序。
    /// </summary>
    event EventHandler PostGenerateQueue;

    /// <summary>
    ///     为BeginSavingUnit事件附加或移除事件处理程序。
    /// </summary>
    event EventHandler<BeginSavingUnitEventArgs> BeginSavingUnit;

    /// <summary>
    ///     为EndSavingUnit事件附加或移除事件处理程序。
    /// </summary>
    event EventHandler<EndSavingUnitEventArgs> EndSavingUnit;

    /// <summary>
    ///     为EndSaving事件附加或移除事件处理程序。
    /// </summary>
    event EventHandler EndSaving;
}
    
/// <summary>
///     "删除"管道接口。
/// </summary>
public interface IDeletingPipeline
{
    /// <summary>
    ///     为PreExecuteSql事件附加或移除事件处理程序。
    /// </summary>
    event EventHandler<PreExecuteCommandEventArgs> PreExecuteCommand;

    /// <summary>
    ///     为PostExecuteSql事件附加或移除事件处理程序。
    /// </summary>
    event EventHandler<PostExecuteCommandEventArgs> PostExecuteCommand;

    /// <summary>
    ///     为BeginDeleting事件附加或移除事件处理程序。
    /// </summary>
    event EventHandler BeginDeleting;

    /// <summary>
    ///     为PostGenerateGroup事件附加或移除事件处理程序。
    /// </summary>
    event EventHandler PostGenerateGroup;

    /// <summary>
    ///     为BeginDeletingGroup事件附加或移除事件处理程序。
    /// </summary>
    event EventHandler<BeginDeletingGroupEventArgs> BeginDeletingGroup;

    /// <summary>
    ///     为EndDeletingGroup事件附加或移除事件处理程序。
    /// </summary>
    event EventHandler<EndDeletingGroupEventArgs> EndDeletingGroup;

    /// <summary>
    ///     为EndDeleting事件附加或移除事件处理程序。
    /// </summary>
    event EventHandler EndDeleting;
}

Obase在保存对象时,会按照保存旧对象,删除对象和保存新对象的顺序来进行保存所有的对象,所以将保存管道和删除管道合并进行讲解。 Obase的总体保存流程和触发事件顺序如下:

  1. 进入保存旧对象方法,并触发ISavingPipeline.BeginSaving事件。
  2. 根据要更新的对象生成包含数个更新映射的集合,循环集合对于每个更新映射都首先触发ISavingPipeline.BeginSavingUnit,而后执行保存逻辑,并且在提交实际操作持久层命令前后依次触发ISavingPipeline.PreExecuteCommand和ISavingPipeline.PostExecuteCommand,最后触发ISavingPipeline.EndSavingUnit。
  3. 结束循环,结束保存旧对象方法。
  4. 进入删除方法,触发IDeletingPipeline.BeginDeleting事件。
  5. 对要删除的对象分组,并触发IDeletingPipeline.PostGenerateGroup事件。
  6. 循环分组后的对象,对于每个对象都首先触发IDeletingPipeline.BeginDeletingGroup,而后执行删除逻辑,并在提交实际操作持久层命令前后依次触发IDeletingPipeline.PreExecuteCommand和IDeletingPipeline.PostExecuteCommand,最后触发IDeletingPipeline.EndDeletingGroup。
  7. 结束循环,触发IDeletingPipeline.EndDeleting事件。
  8. 进入保存新对象方法,根据要保存的新对象生成保存队列,并触发ISavingPipeline.PostGenerateQueue事件。
  9. 根据要新增的对象生成包含数个新增映射的集合,循环集合对于每个更新映射都首先触发ISavingPipeline.BeginSavingUnit,而后执行保存逻辑,并且在提交实际操作持久层命令前后依次触发ISavingPipeline.PreExecuteCommand和ISavingPipeline.PostExecuteCommand,最后触发ISavingPipeline.EndSavingUnit。
  10. 结束循环,触发ISavingPipeline.EndSaving事件,结束保存流程。

其中,BeginSavingUnit和EndSavingUnit事件触发时,会抛出事件数据,其定义如下:

/// <summary>
///     与映射单元相关的事件的数据类。
/// </summary>
public abstract class MappingUnitEventArgs : EventArgs
{
    /// <summary>
    ///     映射单元主对象状态
    /// </summary>
    private readonly eObjectStatus _hostObjectStatus;

    /// <summary>
    ///     映射单元。
    /// </summary>
    private readonly MappingUnit _mappingUnit;


    /// <summary>
    ///     创建MappingUnitEventArgs实例,并指定映射单元。
    /// </summary>
    /// <param name="mappingUnit">映射单元。</param>
    /// <param name="hostObjectStatus">映射单元主对象状态</param>
    protected MappingUnitEventArgs(MappingUnit mappingUnit, eObjectStatus hostObjectStatus)
    {
        _mappingUnit = mappingUnit;
        _hostObjectStatus = hostObjectStatus;
    }

    /// <summary>
    ///     获取映射单元。
    /// </summary>
    public MappingUnit MappingUnit => _mappingUnit;

    /// <summary>
    ///     映射单元主对象状态
    /// </summary>
    public eObjectStatus HostObjectStatus => _hostObjectStatus;
}

    /// <summary>
///     开始保存单元事件数据类
/// </summary>
public class BeginSavingUnitEventArgs : MappingUnitEventArgs
{
    /// <summary>
    ///     创建BeginSavingUnitEventArgs实例,并指定要保存的映射单元。
    /// </summary>
    /// <param name="mappingUnit">映射单元。</param>
    /// <param name="hostObjectStatus">映射单元主对象状态</param>
    public BeginSavingUnitEventArgs(MappingUnit mappingUnit, eObjectStatus hostObjectStatus) : base(mappingUnit,
        hostObjectStatus)
    {
    }
}


/// <summary>
///     结束保存单元事件数据类
/// </summary>
public class EndSavingUnitEventArgs : MappingUnitEventArgs
{
    /// <summary>
    ///     保存过程中发生的异常,如果执行成功则值为NULL。
    /// </summary>
    private readonly Exception _exception;


    /// <summary>
    ///     创建EndSavingUnitEventArgs实例,并指定尝试保存的映射单元和执行过程中发生的异常。
    /// </summary>
    /// <param name="mappingUnit">要保存的映射单元。</param>
    /// <param name="hostObjectStatus">映射单元主对象状态</param>
    /// <param name="exception">异常。</param>
    public EndSavingUnitEventArgs(MappingUnit mappingUnit, eObjectStatus hostObjectStatus,
        Exception exception = null) : base(mappingUnit, hostObjectStatus)
    {
        _exception = exception;
    }

    /// <summary>
    ///     获取保存过程中发生的异常,如果执行成功则值为NULL。
    /// </summary>
    public Exception Exception => _exception;

    /// <summary>
    ///     获取一个值,该值指示保存操作是否执行失败。
    /// </summary>
    public bool Failed => _exception != null;
}

接下来介绍Obase查询的流程和IQueryPipeline的事件触发。

/// <summary>
///     查询管道接口。
/// </summary>
public interface IQueryPipeline
{
    /// <summary>
    ///     为PreExecuteSql事件附加或移除事件处理程序。
    /// </summary>
    event EventHandler<PreExecuteCommandEventArgs> PreExecuteCommand;

    /// <summary>
    ///     为PostExecuteSql事件附加或移除事件处理程序。
    /// </summary>
    event EventHandler<PostExecuteCommandEventArgs> PostExecuteCommand;

    /// <summary>
    ///     为BeginQuery事件附加或移除事件处理程序。
    /// </summary>
    event EventHandler<BeginQueryEventArgs> BeginQuery;

    /// <summary>
    ///     为EndQuery事件附加或移除事件处理程序。
    /// </summary>
    event EventHandler EndQuery;
}

Obase在获得传入的查询表达式后,会按照如下流程进行查询:

  1. 触发IQueryPipeline.BeginQuery事件。
  2. 解析表达式,生成查询链,最终转换为操作持久化层的命令。并且在提交实际操作持久层命令前后依次触发IQueryPipeline.PreExecuteCommand和IQueryPipeline.PostExecuteCommand事件。
  3. 结束查询,触发IQueryPipeline.EndQuery事件。

其中,BeginQuery时会抛出事件数据,其定义如下:

/// <summary>
///     BeginQuery事件数据类。
/// </summary>
public class BeginQueryEventArgs : EventArgs
{
    /// <summary>
    ///     查询表达式。
    /// </summary>
    private readonly Expression _expression;


    /// <summary>
    ///     创建BeginQueryEventArgs实例。
    /// </summary>
    /// <param name="expression">查询表达式。</param>
    public BeginQueryEventArgs(Expression expression)
    {
        _expression = expression;
    }

    /// <summary>
    ///     获取查询表达式。
    /// </summary>
    public Expression Expression => _expression;
}

最后是IDirectlyChangingPipeline直接修改管道,此管道内事件会在直接修改方法(Delete,SetAttributes,IncreaseAttributes)中触发,以下时此管道的定义:

/// <summary>
///     “就地修改”管道接口。
///     “就地修改”是指直接在数据库中修改符合条件的对象,而不是先将对象载入缓存、修改后再写回数据库。包含更改对象属性和删除对象。
/// </summary>
public interface IDirectlyChangingPipeline
{
    /// <summary>
    ///     为PreExecuteSql事件附加或移除事件处理程序。
    /// </summary>
    event EventHandler<PreExecuteCommandEventArgs> PreExecuteCommand;

    /// <summary>
    ///     为PostExecuteSql事件附加或移除事件处理程序。
    /// </summary>
    event EventHandler<PostExecuteCommandEventArgs> PostExecuteCommand;

    /// <summary>
    ///     为BeginDirectlyChanging事件附加或移除事件处理程序。
    /// </summary>
    event EventHandler<BeginDirectlyChangingEventArgs> BeginDirectlyChanging;

    /// <summary>
    ///     为EndDirectlyChanging事件附加或移除事件处理程序。
    /// </summary>
    event EventHandler<EndDirectlyChangingEventArgs> EndDirectlyChanging;
}

在直接修改方法(Delete,SetAttributes,IncreaseAttributes中会按照如下顺序触发事件:

  1. 进入直接修改方法,触发IDirectlyChangingPipeline.BeginDirectlyChanging事件。
  2. 生成具体操作语句,并且在提交实际操作持久层命令前后依次触发IDirectlyChangingPipeline.PreExecuteCommand和IDirectlyChangingPipeline.PostExecuteCommand事件。
  3. 提交完成后,触发IDirectlyChangingPipeline.EndDirectlyChanging事件。

其中BeginDirectlyChanging和EndDirectlyChanging事件会传输如下的事件数据:

/// <summary>
///     与就地修改相关的事件的数据类。
/// </summary>
public abstract class DirectlyChangingEventArgs : EventArgs
{
    /// <summary>
    ///     修改类型。
    /// </summary>
    private readonly eDirectlyChangeType _changeType;

    /// <summary>
    ///     条件表达式。
    /// </summary>
    private readonly Expression _expression;

    /// <summary>
    ///     存储属性新值的字典,键为属性名称,值为属性的新值。
    /// </summary>
    private readonly KeyValuePair<string, object>[] _newValues;

    /// <summary>
    ///     修改的对象类型
    /// </summary>
    private readonly Type _type;


    /// <summary>
    ///     创建DirectlyChangingEventArgs实例,并指定条件表达式和属性新值字典。
    /// </summary>
    /// <param name="expression">条件表达式。</param>
    /// <param name="changeType">修改类型</param>
    /// <param name="objectType">修改的对象类型</param>
    /// <param name="newValues">属性新值字典。</param>
    protected DirectlyChangingEventArgs(Expression expression, eDirectlyChangeType changeType, Type objectType,
        KeyValuePair<string, object>[] newValues = null)
    {
        _expression = expression;
        _changeType = changeType;
        _type = objectType;
        _newValues = newValues;
    }

    /// <summary>
    ///     获取条件表达式。
    /// </summary>
    public Expression Expression => _expression;

    /// <summary>
    ///     获取修改类型。
    /// </summary>
    public eDirectlyChangeType ChangeType => _changeType;

    /// <summary>
    ///     获取存储属性新值的字典,键为属性名称,值为属性的新值。
    /// </summary>
    public KeyValuePair<string, object>[] NewValues => _newValues;

    /// <summary>
    ///     修改的对象类型
    /// </summary>
    public Type Type => _type;
}

/// <summary>
///     BeginDirectlyChanging事件数据类。
/// </summary>
public class BeginDirectlyChangingEventArgs : DirectlyChangingEventArgs
{
    /// <summary>
    ///     创建BeginDirectlyChangingEventArgs实例,并指定条件表达式和属性新值字典。
    /// </summary>
    /// <param name="expression">条件表达式。</param>
    /// <param name="changeType">更改类型</param>
    /// <param name="objectType">修改的对象类型</param>
    /// <param name="attributes">属性新值字典。</param>
    public BeginDirectlyChangingEventArgs(Expression expression, eDirectlyChangeType changeType, Type objectType,
        KeyValuePair<string, object>[] attributes = null) : base(expression, changeType, objectType, attributes)
    {
    }
}

    /// <summary>
///     结束就地修改事件数据类
/// </summary>
public class EndDirectlyChangingEventArgs : DirectlyChangingEventArgs
{
    /// <summary>
    ///     影响的行数
    /// </summary>
    private readonly int _affectedCount;

    /// <summary>
    ///     执行过程中发生的异常,如果执行成功则值为NULL。
    /// </summary>
    private readonly Exception _exception;


    /// <summary>
    ///     创建EndDirectlyChangingEventArgs实例,并指定过滤条件表达式和执行过程中发生的异常。
    /// </summary>
    /// <param name="expression">条件表达式。</param>
    /// <param name="changeType">修改类型</param>
    /// <param name="objectType">修改的对象类型</param>
    /// <param name="affectedCount">影响行数</param>
    /// <param name="newValues">属性新值字典。</param>
    /// <param name="exception">执行过程中发生的异常。</param>
    public EndDirectlyChangingEventArgs(Expression expression, eDirectlyChangeType changeType, Type objectType,
        int affectedCount,
        KeyValuePair<string, object>[] newValues = null, Exception exception = null) : base(expression, changeType,
        objectType,
        newValues)
    {
        _affectedCount = affectedCount;
        _exception = exception;
    }


    /// <summary>
    ///     获取执行过程中发生的异常,如果执行成功则值为NULL。
    /// </summary>
    public Exception Exception => _exception;

    /// <summary>
    ///     获取一个值,该值指示执行过程中是否发生了异常。
    /// </summary>
    public bool Failed => _exception != null;

    /// <summary>
    ///     影响的行数
    /// </summary>
    public int AffectedCount => _affectedCount;
}

此外,四条映射管道都的PreExecuteCommand和PostExecuteCommand均会抛出如下定义的事件数据:

    /// <summary>
///     PreExecuteCommandEventArgs事件的数据类。
/// </summary>
public class PreExecuteCommandEventArgs : EventArgs
{
    /// <summary>
    ///     要执行的存储指令(如Sql语句)。
    /// </summary>
    private readonly object _command;

    /// <summary>
    ///     在查询管道中,表示查询表达式;对于其它管道,该属性为NULL。
    /// </summary>
    private Expression _expression;


    /// <summary>
    ///     创建PreExecuteCommandEventArgs实例。
    /// </summary>
    /// <param name="command">要执行的存储指令(如Sql语句)。</param>
    public PreExecuteCommandEventArgs(object command)
    {
        _command = command;
    }

    /// <summary>
    ///     在查询管道中,获取或设置查询表达式;对于其它管道,该属性为NULL。
    /// </summary>
    public Expression Expression
    {
        get => _expression;
        set => _expression = value;
    }

    /// <summary>
    ///     获取要执行的Sql语句。
    /// </summary>
    /// <summary>
    ///     获取要执行的存储指令(如Sql语句)。
    /// </summary>
    public object Command => _command;
}

    /// <summary>
///     PostExecuteSql事件数据类。
/// </summary>
public class PostExecuteCommandEventArgs : EventArgs
{
    /// <summary>
    ///     受影响的行数。
    /// </summary>
    private readonly int _affectedCount;

    /// <summary>
    ///     要执行的存储指令(如Sql语句)。
    /// </summary>
    private readonly object _command;

    /// <summary>
    ///     执行Sql语句的过程中发生的异常,未发生异常则为Null。
    /// </summary>
    private readonly Exception _exception;

    /// <summary>
    ///     执行Sql语句所消耗的时间,以毫秒为单位。
    /// </summary>
    private readonly int _timeConsumed;

    /// <summary>
    ///     在查询管道中,表示查询表达式;对于其它管道,该属性为NULL。
    /// </summary>
    private Expression _expression;

    /// <summary>
    ///     创建PostExecuteSqlEventArgs实例,并指定要执行的存储指令(如Sql语句)和执行消耗的时间。
    /// </summary>
    /// <param name="command">要执行的存储指令(如Sql语句)。</param>
    /// <param name="timeConsumed">执行指令所消耗的时间,以毫秒为单位。</param>
    /// <param name="affectedCount">受影响的行数。</param>
    public PostExecuteCommandEventArgs(object command, int timeConsumed, int affectedCount)
    {
        _command = command;
        _timeConsumed = timeConsumed;
        _affectedCount = affectedCount;
    }

    /// <summary>
    ///     创建PostExecuteSqlEventArgs实例,并指定要执行的存储指令(如Sql语句)、执行消耗的时间、以及执行过程中发生的异常。
    /// </summary>
    /// <param name="command">要执行的存储指令(如Sql语句)。</param>
    /// <param name="timeConsumed">执行指令所消耗的时间,以毫秒为单位。</param>
    /// <param name="exception">执行指令过程中发生的异常</param>
    public PostExecuteCommandEventArgs(object command, int timeConsumed, Exception exception)
    {
        _command = command;
        _timeConsumed = timeConsumed;
        _exception = exception;
    }

    /// <summary>
    ///     获取执行Sql语句所消耗的时间,以毫秒为单位。
    /// </summary>
    public int TimeConsumed => _timeConsumed;

    /// <summary>
    ///     获取执行Sql语句的过程中发生的异常,未发生异常则为Null。
    /// </summary>
    public Exception Exception => _exception;

    /// <summary>
    ///     在查询管道中,获取或设置查询表达式;对于其它管道,该属性为NULL。
    /// </summary>
    public Expression Expression
    {
        get => _expression;
        set => _expression = value;
    }

    /// <summary>
    ///     获取受影响的行数。
    /// </summary>
    public int AffectedCount => _affectedCount;

    /// <summary>
    ///     获取要执行的存储指令(如Sql语句)。
    /// </summary>
    public object Command => _command;
}

以上就是映射管道的事件触发顺序,用户可以根据自身要拓展的逻辑自定义订阅其中的事件,操作相应的事件数据,实现功能扩展。

没有找到您需要的文档?

您还可以通过人工服务在线咨询,服务时间为每天上午9点至下午6点。

If you can't find required answer, get in touch with us online. We provide service from 9:00 to 18:00.

让编程成为一件快乐的事
现在开始