看起来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);
}
}
我想要实现的就是插入我的Cat
具有由 NHibernate 使用生成的 ID 的记录SELECT MAX(ID) FROM Cats
在任何之前插入。在任何提交之后执行 Session.Flush 都不起作用。我使用 SQL Server Profiler 进行了一些调查,并且此 sql stetement 仅执行一次(在第一次插入时) - 其他插入不会强制检索实际的 MAX(ID)。我知道像 HiLo 这样的其他算法更好,但我无法取代它。
正如您所发现的,NHibernate Increment id 生成器不适用于多用户环境。您声明使用 HiLo 生成器不是一个选项,因此您只剩下以下选项:
使用本机生成器并更改 id 列以使用数据库支持的身份机制
使用分配的生成器并编写代码来确定下一个有效的 id
创建一个自定义生成器,您可以在其中实现界面来完成您需要的操作
下面是自定义生成器的示例代码,它使用通用过程来获取给定表的 ID。这种方法的主要问题是您必须将代码包装在类似工作单元 http://nhibernate.info/doc/patternsandpractices/nhibernate-and-the-unit-of-work-pattern.html模式以确保“select max(id) ...”和插入由同一数据库事务覆盖。link 具有连接此自定义生成器所需的 XML 映射。
using System;
using System.Collections.Generic;
using System.Data;
using NHibernate.Dialect;
using NHibernate.Engine;
using NHibernate.Id;
using NHibernate.Persister.Entity;
using NHibernate.Type;
namespace YourCompany.Stuff
{
public class IdGenerator : IIdentifierGenerator, IConfigurable
{
private string _tableName;
// The "select max(id) ..." query will go into this proc:
private const string DefaultProcedureName = "dbo.getId";
public string ProcedureName { get; protected set; }
public string TableNameParameter { get; protected set; }
public string OutputParameter { get; protected set; }
public IdGenerator()
{
ProcedureName = DefaultProcedureName;
TableNameParameter = "@tableName";
OutputParameter = "@newID";
}
public object Generate(ISessionImplementor session, object obj)
{
int newId;
using (var command = session.Connection.CreateCommand())
{
var tableName = GetTableName(session, obj.GetType());
command.CommandType = CommandType.StoredProcedure;
command.CommandText = ProcedureName;
// Set input parameters
var parm = command.CreateParameter();
parm.Value = tableName;
parm.ParameterName = TableNameParameter;
parm.DbType = DbType.String;
command.Parameters.Add(parm);
// Set output parameter
var outputParameter = command.CreateParameter();
outputParameter.Direction = ParameterDirection.Output;
outputParameter.ParameterName = OutputParameter;
outputParameter.DbType = DbType.Int32;
command.Parameters.Add(outputParameter);
// Execute the stored procedure
command.ExecuteNonQuery();
var id = (IDbDataParameter)command.Parameters[OutputParameter];
newId = int.Parse(id.Value.ToString());
if (newId < 1)
throw new InvalidOperationException(
string.Format("Could not retrieve a new ID with proc {0} for table {1}",
ProcedureName,
tableName));
}
return newId;
}
public void Configure(IType type, IDictionary<string, string> parms, Dialect dialect)
{
_tableName = parms["TableName"];
}
private string GetTableName(ISessionImplementor session, Type objectType)
{
if (string.IsNullOrEmpty(_tableName))
{
//Not set by configuration, default to the mapped table of the actual type from runtime object:
var persister = (IJoinable)session.Factory.GetClassMetadata(objectType);
var qualifiedTableName = persister.TableName.Split('.');
_tableName = qualifiedTableName[qualifiedTableName.GetUpperBound(0)]; //Get last string
}
return _tableName;
}
}
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)