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

NHibernate:如何在调用session.Save()前为实体分配ID?

如何在调用session.Save()前为NHibernate实体分配HiLo生成的ID?

我需要在将实体保存到数据库前为其分配ID。目前使用HiLo生成器,但ID仅在调用session.Save(object)后才会分配。相关代码示例如下:

var std1 = new Student
{
    FirstName = Guid.NewGuid().ToString(),
    LastName = Guid.NewGuid().ToString()
};

//--- 我需要在这里(对象构造完成后)就分配好唯一ID

Console.WriteLine($">>> StudentId before {std1.ID} Name {std1.FirstName}");
Console.WriteLine("<press enter>");
Console.ReadLine();
session.Save(std1);

//--- 现在只有调用Save后才会分配ID,这对我的需求来说太晚了

Console.WriteLine($">>> StudentId after {std1.ID}");

Student实体的映射文件定义如下:

<?xml version = "1.0" encoding = "utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="CSharpTests" namespace="CSharpTests">

    <class name="Student" table="student">
        <id name="ID" column="id">
            <generator class="hilo">
                <param name="table">students_hilo</param>
                <param name="column">next_hi</param>
                <param name="max_lo">100</param>
            </generator>
        </id>
        <property name="LastName" column="last_name" type="String"/>
        <property name="FirstName" column="first_name" type="String"/>
    </class>

</hibernate-mapping>

解决方案

当然可以在调用session.Save()前分配HiLo生成的ID,有两种常用方式:

1. 使用session.Lock()触发ID生成

调用session.Lock()方法并传入LockMode.None,会让NHibernate为实体分配ID,但不会将实体持久化到数据库,也不会触发任何数据库锁操作:

var std1 = new Student
{
    FirstName = Guid.NewGuid().ToString(),
    LastName = Guid.NewGuid().ToString()
};

// 提前生成ID
session.Lock(std1, LockMode.None);

// 此时std1.ID已经被分配
Console.WriteLine($">>> StudentId before {std1.ID} Name {std1.FirstName}");
Console.WriteLine("<press enter>");
Console.ReadLine();
session.Save(std1);

Console.WriteLine($">>> StudentId after {std1.ID}");

这种方式的好处是完全由NHibernate管理ID生成逻辑,避免手动操作可能带来的冲突。

2. 手动调用标识符生成器

直接从SessionFactory获取HiLo生成器,手动为实体分配ID:

var std1 = new Student
{
    FirstName = Guid.NewGuid().ToString(),
    LastName = Guid.NewGuid().ToString()
};

// 获取实体对应的标识符生成器
var generator = session.SessionFactory.GetIdentifierGenerator(typeof(Student));
// 生成ID并赋值给实体
std1.ID = (int)generator.Generate(session, std1);

// 此时ID已分配完成
Console.WriteLine($">>> StudentId before {std1.ID} Name {std1.FirstName}");

需要注意的是,要根据你的ID类型(比如int、long)调整强制转换的类型。

原理说明

HiLo生成器的工作机制是先从数据库的HiLo表中获取一个hi值,然后在内存中生成lo值(范围0到配置的max_lo),最终ID由hi * (max_lo + 1) + lo计算得出。因此提前生成ID完全可行,因为hi值一旦获取,lo值在内存中分配不会重复,也不会与其他进程/线程生成的ID冲突。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 09:25:19