如何使用fluent-nhibernate更改多列索引中的列顺序?

时间:2009-12-09 18:48:26

标签: fluent-nhibernate

如何更改多列索引中的列顺序?
即:

mapping.References(x => x.SomeReference).SetAttribute("index", "IX_index");
mapping.Map(x => x.SomeField).SetAttribute("index", "IX_index");

生成以下架构:

create index IX_index on ApplicantProgramDatas (SomeField, SomeReferenceId)

但我想得到:

create index IX_index on ApplicantProgramDatas (SomeReferenceId, SomeField)

3 个答案:

答案 0 :(得分:4)

您可以使用< database-object>在NHibernate中定义索引。或IAuxiliaryDatabaseObject。

在hbm.xml文件中:

<hibernate-mapping xmlns="urn:nhiernate-mapping-2.2">
  <database-object>
     <create>VALID SQL</create>
     <drop>VALID SQL</create>
  </database-object>
</hibernate-mapping>

N.B。 &LT;数据库对象&gt;可以在同一个hbm.xml文件中的类映射之前或之后进行,允许您将索引定义,触发器等保留在它们应用的对象中。

另一个选项是NHibernate.Mapping.IAuxiliaryDatabaseObject:

namespace NHibernate.Mapping {
    public interface IAuxiliaryDatabaseObject : IRelationalModel {
        void AddDialectScope(string dialectName);
        bool AppliesToDialect(Dialect dialect);
        void SetParameterValues(IDictionary<string, string> parameters);
    }
    public interface IRelationalModel {
        string SqlCreateString(Dialect dialect, IMapping p, string defaultCatalog, string defaultSchema);
        string SqlDropString(Dialect dialect, string defaultCatalog, string defaultSchema);
    }
}

鉴于您正在使用Fluent NHibernate,IAuxiliaryDatabaseObject可能会更适合您。只需在构建时公开您的配置,然后调用:

var sqlCreate = "CREATION SCRIPT";
var sqlDrop = "DROP SCRIPT";    
cfg.AddAuxiliaryDatabaseObject(new SimpleAuxiliaryDatabaseObject(sqlCreate, sqlDrop));

N.B。 NHibernate.Mapping.SimpleAuxiliaryDatabaseObject是NHibernate的一部分。如果您只需要为数据库对象提供创建/删除脚本,则无需自己编写。

我快速查看了Fluent NHibernate代码库,但没有看到对IAuxiliaryDatabaseObject的任何直接支持。所以这是暴露配置对象并自己提供所有IAuxiliaryDatabaseObjects的问题。编写一些扫描遍历映射程序集的代码来查找实现IAuxiliaryDatabaseObject的类型然后对它们进行预处理以传递给cfg.AddAuxiliaryDatabaseObject(obj)并不会太困难。

您可以在NHibernate文档中找到有关辅助数据库对象的更多信息:

http://nhibernate.info/doc/nh/en/index.html#mapping-database-object

答案 1 :(得分:3)

我想这是不可能的。 'FluentNHibernate.MappingModel.MappedMembers.AcceptVisitor()'在引用之前迭代属性:

        foreach (var collection in Collections)
            visitor.Visit(collection);

        foreach (var property in Properties)
            visitor.Visit(property);

        foreach (var reference in References)
            visitor.Visit(reference);

因此,在多列索引中引用之前,您将始终拥有属性。

BTW没有一个ORM可以让你设置非平凡的索引选项,如聚类,过滤等。

答案 2 :(得分:2)

我建议覆盖SchemaExport。通过反射有私有字段访问器,它需要完全信任模式。如果这种方法不适合您的需求,请考虑重写SchemaExport(相对较轻的类)


using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Text;
using FluentNHibernate.Cfg;
using FluentNHibernate.Cfg.Db;
using FluentNHibernate.Mapping;
using NHibernate.Cfg;
using NHibernate.Tool.hbm2ddl;

namespace FluentNHib
{

    public class Master
    {
        public int Id { get; set; }
    }

    public class Child
    {
        public int Id { get; set; }
        [MCIndex("A", 0)]
        public Master Master { get; set; }
        [MCIndex("A", 1)]
        public string Name { get; set; }
    }

    public class MCIndexAttribute : Attribute
    {
        public string indexName;
        public int indexOrder;

        public MCIndexAttribute(string indexName, int i)
        {
            this.indexName = indexName;
            this.indexOrder = i;
        }
    }

    public class MasterMap : ClassMap
    {
        public MasterMap()
        {
            Id(x => x.Id);
        }
    }

    public class ChildMap : ClassMap
    {
        public ChildMap()
        {
            Id(x => x.Id);
            References(x => x.Master).Index("A");
            Map(x => x.Name).Index("A");

        }
    }

    class MySchemaExport : SchemaExport
    {
        internal struct MCIndexField
        {
            internal int index;
            internal string Name;

        }

        internal class MCIndex
        {
            internal string IndexName;
            public readonly IList fields = new List();
            public string Table;

            public void AddField(string name, int indexOrder)
            {
                fields.Add(new MCIndexField {index = indexOrder, Name = name});
            }
        }

        private readonly Dictionary indexes = new Dictionary();

        MCIndex ByName(string name, string table)
        {
            MCIndex result;
            if (!indexes.TryGetValue(name, out result))
            {
                result = new MCIndex
                    {
                        IndexName = name
                    };
                indexes.Add(name, result);
            }
            return result;
        }

        public MySchemaExport(Configuration cfg) : base(cfg)
        {
            foreach (var type in typeof(ChildMap).Assembly.GetTypes())
            {
                foreach (var prop in type.GetProperties())
                {
                    var attr = prop.GetCustomAttributes(typeof (MCIndexAttribute), true);
                    if (attr.Length == 1)
                    {
                        var attribute = (MCIndexAttribute) attr[0];
                        ByName(attribute.indexName, type.Name).AddField(prop.Name, attribute.indexOrder);
                    }
                }
            }


            var createSqlProp = typeof(SchemaExport).GetField("createSQL", BindingFlags.NonPublic | BindingFlags.Instance);
            var wasSql = createSqlProp.GetValue(this);

            var sb = new StringBuilder();
            sb.AppendLine("");
            foreach (var mcIndex in indexes)
            {
                sb.AppendLine(string.Format("create index {0} on {1} ({2})", mcIndex.Value.IndexName, mcIndex.Value.Table, mcIndex.Value.fields));
            }
            createSqlProp.SetValue(this, wasSql + sb.ToString());
        }
    }

    class Program
    {

        private static void BuildSchema(Configuration config)
        {
            new MySchemaExport(config)
                .Create(s =>
                            {
                                Debug.WriteLine(s);
                            }, true);
        }

        const string fileName = "c:\\temp\\temp.fdb";

        private static string GetConnectionString()
        {
            const string userName = "sysdba";
            const string password = "masterkey";
            return String.Format("ServerType=1;User={0};Password={1};Dialect=3;Database={2}", userName, password, fileName);
        }

        private static FluentConfiguration Configurate()
        {
            var fbc = new FirebirdConfiguration();
            return Fluently.Configure()
            .Database(fbc.ShowSql().ConnectionString(GetConnectionString()))
                .Mappings(m => m.FluentMappings
                    .AddFromAssemblyOf()
                )
              .ExposeConfiguration(BuildSchema);
        }

        static void Main(string[] args)
        {
            FluentConfiguration fluentConfiguration = Configurate();

            Configuration cfg = fluentConfiguration.BuildConfiguration();
        }
    }
}