流畅的nHibernate,Hi-Lo表,每行使用一个实体

时间:2012-07-09 20:28:59

标签: nhibernate fluent-nhibernate

有没有办法指定一个用于Hi-Lo值的表,每个实体都有一个每行条目,通过约定(虽然仍然有nHibernate为你创建表结构)?我想复制Phil Haydon关于here的博客,但无需手动管理表格。就目前而言,只有当你已经在表格中为'TableKey'创建了适当的条目时,才能将他的每表行代码迁移到它自己的约定。

或者,这可以通过XML映射吗?

如果所有其他方法都失败了,那么使用自定义生成器的另一个合适的选择是la this post吗?

3 个答案:

答案 0 :(得分:8)

Fabio Maulo talked about this在他的一个代码映射帖子中。

按代码示例映射:

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()));

答案 1 :(得分:2)

对于Fluent NHibernate的用户,Anthony Dewhirst在这里发布了一个很好的解决方案:http://www.anthonydewhirst.blogspot.co.uk/2012/02/fluent-nhibernate-solution-to-enable.html

答案 2 :(得分:2)

基于Anthony Dewhirst已经很出色的解决方案,我最终得到了以下内容,这增加了一些改进:

  • 添加接受标准,以便它不会尝试处理非整数Id类型(例如Guid),也不会踩踏明确设置了生成器的Id映射
  • 脚本生成需要考虑方言
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));
    }
}