2009-12-09 77 views
6

如何更改多列索引中的列順序?
即:如何使用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) 
+0

+1你找到一個方法來做到這一點最終會?我有同樣的問題。 – Groo 2010-11-04 14:33:38

+1

您是否嘗試交換映射聲明的順序? (即使它起作用,也是一種軟糖!) – UpTheCreek 2010-11-10 11:08:58

+0

@UpTheCreek:正如Ben在下面說的,我認爲它不起作用。如果我有多個多列索引,則該方法無論如何都會失敗,因爲它會強制單列成爲* all *索引中最頂端的索引列。 – Groo 2010-11-11 12:03:13

回答

4

您可以定義使用<數據庫對象>或IAuxiliaryDatabaseObject NHibernate的一個指標。

在hbm.xml文件中:

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

注: <數據庫對象>可以在同一個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); 
    } 
} 

假設你使用功能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

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沒有奧姆斯會給你設置不平凡的指數期權喜歡集羣,過濾等

+0

謝謝。在這種情況下,您是否知道將某種自定義(手寫)架構包含到配置中的方法?我寧願在一個地方創建與創建數據庫相關的所有SQL。我想我可以在NHibernate構建模式的其餘部分之後執行普通的SQL來添加索引。 – Groo 2010-11-11 12:06:39

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(); 
     } 
    } 
}
+0

謝謝,不是一個壞建議。但是有一些注意事項:a)我認爲你的通用括號丟失了'''''b)'createSQL'似乎在FluentHib中返回了一個字符串數組。 1.1,c)你實際上從來沒有通過索引號實際排序屬性,d)'fields'列表本身不能正確渲染,在'sb.AppendLine'中。我可以很容易地解決這些問題,但是我實際上更喜歡在我的映射類中使用索引而不是實際的實體,所以我可能會重寫其中很大一部分來將它們移到那裏。不過,你回答了我的問題,並給了我一個好主意。 – Groo 2010-11-15 13:14:28