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

发布于 2024-08-15 02:10:38 字数 436 浏览 2 评论 0原文

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

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)

How to change the column order in a multi-column index?
I.e:

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

Produces the following Schema:

create index IX_index on ApplicantProgramDatas (SomeField, SomeReferenceId)

But I want to get:

create index IX_index on ApplicantProgramDatas (SomeReferenceId, SomeField)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

清泪尽 2024-08-22 02:10:38

您可以使用在 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>

NB可以位于同一 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));

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

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

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

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

You can define an index in NHibernate using <database-object> or IAuxiliaryDatabaseObject.

In a hbm.xml file:

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

N.B. <database-object> can go before or after a class mapping in the same hbm.xml file allowing you to keep your index definitions, triggers, etc. with the object to which they apply.

The other option is 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);
    }
}

Given that you're using Fluent NHibernate, IAuxiliaryDatabaseObject will probably work better for you. Just expose your configuration when building it and then call:

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

N.B. NHibernate.Mapping.SimpleAuxiliaryDatabaseObject is part of NHibernate. You don't have to write it yourself if all you need to do is supply create/drop scripts for a database object.

I took a quick look in the Fluent NHibernate codebase and didn't see any direct support for IAuxiliaryDatabaseObject. So it is a matter of exposing your configuration object and supplying all your IAuxiliaryDatabaseObjects yourself. It wouldn't be too difficult to write some code that scan through your mapping assembly looking for types that implement IAuxiliaryDatabaseObject and then foreach'ing over them to pass to cfg.AddAuxiliaryDatabaseObject(obj).

You can find more information about auxiliary database objects in the NHibernate docs:

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

ι不睡觉的鱼゛ 2024-08-22 02:10:38

我想这是不可能的。 “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);

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

顺便说一句,没有一个 ORM 能让你设置重要的索引选项,比如集群、过滤等。

I guess it is impossible. 'FluentNHibernate.MappingModel.MappedMembers.AcceptVisitor()' iterates properties before references:

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

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

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

As a result, you will always have properties before references in multi-column index.

BTW none of the ORMs will give you ability to set non-trivial index options like clustered, filtered, etc.

巴黎夜雨 2024-08-22 02:10:38

让我建议覆盖 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();
        }
    }
}

Let me suggest to override SchemaExport. There is private field accessor via reflection, it requires full trust mode. If this approach does not suit your needs, consider rewriting SchemaExport (relatively light class)


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();
        }
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文