有没有办法通过约定指定用于 Hi-Lo 值的表,每个实体都有一个每行条目(同时仍然让 nHibernate 为您创建表结构)?我想复制 Phil Haydon 在这里写的博客,但不必手动管理表格。就目前而言,仅当您已经在表中为“TableKey”创建了适当的条目时,将他的每表行代码迁移到它自己的约定才会起作用。
或者,这可以通过 XML 映射实现吗?
如果所有其他方法都失败了,那么使用自定义生成器的唯一其他合适的选择是,比如这篇文章吗?
Fabio Maulo在他的一篇按代码映射的帖子中谈到了这一点。
通过代码示例映射:
mapper.BeforeMapClass += (mi, type, map) =>
map.Id(idmap => idmap.Generator(Generators.HighLow,
gmap => gmap.Params(new
{
table = "NextHighValues",
column = "NextHigh",
max_lo = 100,
where = string.Format(
"EntityName = '{0}'", type.Name.ToLowerInvariant())
})));
对于 FluentNHibernate,您可以执行以下操作:
public class PrimaryKeyConvention : IIdConvention
{
public void Apply(IIdentityInstance instance)
{
var type = instance.EntityType.Name;
instance.Column(type + "Id");
instance.GeneratedBy.HiLo(type, "NextHigh", "100",
x => x.AddParam("where", String.Format("EntityName = '{0}'", type));
}
}
此外,Fabio 还解释了如何使用它IAuxiliaryDatabaseObject
来创建 Hi-Lo 脚本。
private static IAuxiliaryDatabaseObject CreateHighLowScript(
IModelInspector inspector, IEnumerable<Type> entities)
{
var script = new StringBuilder(3072);
script.AppendLine("DELETE FROM NextHighValues;");
script.AppendLine(
"ALTER TABLE NextHighValues ADD EntityName VARCHAR(128) NOT NULL;");
script.AppendLine(
"CREATE NONCLUSTERED INDEX IdxNextHighValuesEntity ON NextHighValues "
+ "(EntityName ASC);");
script.AppendLine("GO");
foreach (var entity in entities.Where(x => inspector.IsRootEntity(x)))
{
script.AppendLine(string.Format(
"INSERT INTO [NextHighValues] (EntityName, NextHigh) VALUES ('{0}',1);",
entity.Name.ToLowerInvariant()));
}
return new SimpleAuxiliaryDatabaseObject(
script.ToString(), null, new HashedSet<string> {
typeof(MsSql2005Dialect).FullName, typeof(MsSql2008Dialect).FullName
});
}
你会像这样使用它:
configuration.AddAuxiliaryDatabaseObject(CreateHighLowScript(
modelInspector, Assembly.GetExecutingAssembly().GetExportedTypes()));
对于 Fluent NHibernate 的用户,Anthony Dewhirst 在这里发布了一个不错的解决方案:http ://www.anthonydewhirst.blogspot.co.uk/2012/02/fluent-nhibernate-solution-to-enable.html
在 Anthony Dewhirst 已经非常出色的解决方案的基础上,我得到了以下结果,它增加了一些改进:
public class HiLoIdGeneratorConvention : IIdConvention, IIdConventionAcceptance
{
public const string EntityColumnName = "entity";
public const string MaxLo = "500";
public void Accept(IAcceptanceCriteria<IIdentityInspector> criteria)
{
criteria
.Expect(x => x.Type == typeof(int) || x.Type == typeof(uint) || x.Type == typeof(long) || x.Type == typeof(ulong)) // HiLo only works with integral types
.Expect(x => x.Generator.EntityType == null); // Specific generator has not been mapped
}
public void Apply(IIdentityInstance instance)
{
instance.GeneratedBy.HiLo(TableGenerator.DefaultTableName, TableGenerator.DefaultColumnName, MaxLo,
builder => builder.AddParam(TableGenerator.Where, string.Format("{0} = '{1}'", EntityColumnName, instance.EntityType.FullName)));
}
public static void CreateHighLowScript(NHibernate.Cfg.Configuration config)
{
var dialect = Activator.CreateInstance(Type.GetType(config.GetProperty(NHibernate.Cfg.Environment.Dialect))) as Dialect;
var script = new StringBuilder();
script.AppendFormat("DELETE FROM {0};", TableGenerator.DefaultTableName);
script.AppendLine();
script.AppendFormat("ALTER TABLE {0} {1} {2} {3} NOT NULL;", TableGenerator.DefaultTableName, dialect.AddColumnString, EntityColumnName, dialect.GetTypeName(SqlTypeFactory.GetAnsiString(128)));
script.AppendLine();
script.AppendFormat("CREATE NONCLUSTERED INDEX IX_{0}_{1} ON {0} ({1} ASC);", TableGenerator.DefaultTableName, EntityColumnName);
script.AppendLine();
if (dialect.SupportsSqlBatches)
{
script.AppendLine("GO");
script.AppendLine();
}
foreach (var entityName in config.ClassMappings.Select(m => m.EntityName).Distinct())
{
script.AppendFormat("INSERT INTO [{0}] ({1}, {2}) VALUES ('{3}',1);", TableGenerator.DefaultTableName, EntityColumnName, TableGenerator.DefaultColumnName, entityName);
script.AppendLine();
}
if (dialect.SupportsSqlBatches)
{
script.AppendLine("GO");
script.AppendLine();
}
config.AddAuxiliaryDatabaseObject(new SimpleAuxiliaryDatabaseObject(script.ToString(), null));
}
}