You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

替换SQL Server触发器,用NHibernate实现Code字段自动填充的更优方案

替代触发器的NHibernate Code字段填充优化方案

不用先插再更,直接在插入前处理逻辑就行,给你几个实用的方案:

1. 业务代码层前置处理(最简单直接)

在调用NHibernate的Save/SaveOrUpdate方法前,直接检查实体的Code字段,为空就生成值,一步完成插入:

var yourEntity = new YourEntity();
// 用户已设置Code则跳过,为空自动生成
if (string.IsNullOrWhiteSpace(yourEntity.Code))
{
    yourEntity.Code = GenerateUniqueCode(); // 这里实现你的Code生成规则,比如GUID截取、自增编号等
}

using (var session = sessionFactory.OpenSession())
using (var tx = session.BeginTransaction())
{
    session.Save(yourEntity);
    tx.Commit();
}

这种方式逻辑直观,无额外NHibernate配置,适合小项目或单一实体场景。批量插入时循环处理每个实体即可。

2. 用NHibernate拦截器统一处理(全局复用)

如果多个实体需要类似逻辑,或不想在业务代码里重复判断,用IInterceptor集中处理:

实现拦截器

public class CodeAutoFillInterceptor : EmptyInterceptor
{
    public override bool OnSave(object entity, object id, object[] state, string[] propertyNames, IType[] types)
    {
        // 仅处理目标实体类型
        if (entity is YourEntity targetEntity && string.IsNullOrWhiteSpace(targetEntity.Code))
        {
            var newCode = GenerateUniqueCode();
            targetEntity.Code = newCode;
            
            // 更新NHibernate状态数组,确保生成的Code能写入数据库
            int codePropIndex = Array.IndexOf(propertyNames, nameof(YourEntity.Code));
            if (codePropIndex >= 0)
            {
                state[codePropIndex] = newCode;
            }
            return true; // 通知NHibernate实体状态已修改
        }
        return base.OnSave(entity, id, state, propertyNames, types);
    }

    // 自定义Code生成逻辑,按需调整
    private string GenerateUniqueCode()
    {
        return Guid.NewGuid().ToString("N").Substring(0, 8);
    }
}

注册拦截器

可全局注册(所有Session生效)或单个Session指定:

// 全局注册
var config = new Configuration();
config.SetInterceptor(new CodeAutoFillInterceptor());
var sessionFactory = config.BuildSessionFactory();

// 单个Session生效
using (var session = sessionFactory.OpenSession(new CodeAutoFillInterceptor()))
{
    // 执行Session操作
}

此方案将Code生成逻辑与业务代码解耦,所有保存操作自动触发检查,适合中大型项目。

3. 用NHibernate事件监听器(生命周期事件处理)

和拦截器类似,事件监听器是NHibernate生命周期事件的扩展点,适合监听多阶段生命周期的场景,比如实现IPreInsertEventListener:

实现事件监听器

public class CodePreInsertListener : IPreInsertEventListener
{
    public bool OnPreInsert(PreInsertEvent @event)
    {
        if (@event.Entity is YourEntity targetEntity && string.IsNullOrWhiteSpace(targetEntity.Code))
        {
            var newCode = GenerateUniqueCode();
            targetEntity.Code = newCode;
            
            // 更新插入状态数组,确保值写入数据库
            int codePropIndex = Array.IndexOf(@event.Persister.PropertyNames, nameof(YourEntity.Code));
            if (codePropIndex >= 0)
            {
                @event.State[codePropIndex] = newCode;
            }
        }
        return false; // 返回false继续执行默认插入流程
    }

    private string GenerateUniqueCode()
    {
        return $"CODE_{DateTime.Now:yyyyMMddHHmmss}_{Guid.NewGuid().ToString("N").Substring(0,4)}";
    }
}

注册监听器

var config = new Configuration();
var listenerRegistry = config.EventListeners;
// 添加自定义监听器到前置插入事件列表
listenerRegistry.PreInsertEventListeners = 
    new IPreInsertEventListener[] { new CodePreInsertListener() }
    .Concat(listenerRegistry.PreInsertEventListeners ?? Array.Empty<IPreInsertEventListener>())
    .ToArray();

var sessionFactory = config.BuildSessionFactory();

注意事项

  • Code唯一性保障:若需全局唯一,生成逻辑要考虑并发场景,比如调用数据库序列(NHibernate的SequenceGenerator)或用分布式ID生成器,避免重复。
  • 批量插入支持:三个方案均支持批量插入,拦截器和事件监听器会自动处理每个实体。
  • 性能优势:均为单次INSERT操作,比「插入+更新」减少一次数据库交互,降低事务内锁开销。

内容的提问来源于stack exchange,提问作者eray

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 15:50:49