如何在使用 NHibernate 进行任何插入之前增加 ID
看起来 NH 仅获取 MAX(ID) 一次,首先插入,然后在内部存储该值,这会在其他进程插入数据时给我带来一些问题。然后我没有实际的 ID,并且抛出重复键异常。
让我们假设我们有表 Cats
CREATE TABLE Cats(ID int, Name varchar(25))
然后我们用 FluentNhibernate 完成了相应的映射
public class CatMap : ClassMap<Cat>
{
public CatMap()
{
Id(m=>m.ID).GeneratedBy.Increment();
Map(m=>.Name);
}
}
我想要实现的就是使用 SELECT MAX 插入带有 NHibernate 生成的 ID 的
在任何之前插入。在任何提交之后执行 Session.Flush 都不起作用。我使用 SQL Server Profiler 进行了一些调查,并且此 sql stetement 仅执行一次(在第一次插入时) - 其他插入不会强制检索实际的 MAX(ID)。我知道像 HiLo 这样的其他算法更好,但我无法取代它。Cat
记录(ID) FROM Cats
It looks like NH gets MAX(ID) only once, at first insert and then stores this value internally, this causes me some problems when other processes inserts data. Then I have not actual ID and duplicate key exception is thrown.
Lets imagine we have table Cats
CREATE TABLE Cats(ID int, Name varchar(25))
Then we have corresponding mapping done with FluentNhibernate
public class CatMap : ClassMap<Cat>
{
public CatMap()
{
Id(m=>m.ID).GeneratedBy.Increment();
Map(m=>.Name);
}
}
All I want to achieve is to insert my Cat
records with ID's generated by NHibernate using SELECT MAX(ID) FROM Cats
before any insert. Executing Session.Flush after any commit dosnt work. I'v done some investigation using SQL Server profiler, and this sql stetement is executed only once (at first insert) - other inserts doesnt force to retreive actual MAX(ID). I know that other algorithms like HiLo are better, but I cant replace it.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
正如您所发现的,NHibernate Increment id 生成器不适用于多用户环境。您声明使用 HiLo 生成器不是一个选项,因此您只剩下以下选项:
使用本机生成器并更改 id 列以使用数据库支持的身份机制
使用分配的生成器并编写代码来确定下一个有效 id
创建自定义生成器,其中你实现了IIdentifierGenerator 接口来执行您需要的操作
下面是自定义生成器的示例代码它使用通用过程来获取给定表的 ID。这种方法的主要问题是您必须将代码包装在类似 工作单元 模式,以确保“select max(id) ...”和插入由同一数据库事务覆盖。IIdentifierGenerator 链接包含连接此自定义生成器所需的 XML 映射。
As you found out, the NHibernate Increment id generator was not intended for use in a multi-user environment. You state that using a HiLo generator is not an option so you're left with these options:
use the Native generator and change the id column to use the database supported identity mechanism
use the Assigned generator and write code to determine the next valid id
create a Custom generator where you implement the IIdentifierGenerator interface to do what you need
Below is sample code for a custom generator that uses a generalized proc to get an ID for a given table. The main issue with this approach is that you must wrap the code in something like a Unit of Work pattern to ensure the 'select max(id) ..." and the insert are covered by the same database transaction. The IIdentifierGenerator link has the XML mapping you need to wire up this custom generator.