2009-12-09 8 views
6

Jak zmienić kolejność kolumn w indeksie z wieloma kolumnami?
tj:Jak zmienić kolejność kolumn w indeksie wielu kolumn przy użyciu fluent-nhibernate?

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

Produkuje następujący schemat:

create index IX_index on ApplicantProgramDatas (SomeField, SomeReferenceId) 

Ale chcę dostać:

create index IX_index on ApplicantProgramDatas (SomeReferenceId, SomeField) 
+0

+1 znalazłaś sposób, aby zrobić to w końcu?Mam ten sam problem. – Groo

+1

Czy próbowałeś zamieniać kolejność deklaracji mapowania? (trochę krówki, nawet jeśli to działa!) – UpTheCreek

+0

@UpTheCreek: Ben powiedział poniżej, myślę, że to nie działa. A to podejście i tak by się nie powiodło, gdybym miał więcej niż jeden indeks wielokolumnowy, ponieważ zmusiłby on kolumnę, by była najwyższą kolumną indeksu w indeksach * all *. – Groo

Odpowiedz

4

Można zdefiniować indeks w NHibernate przy użyciu < bazy obiekt > lub IAuxiliaryDatabaseObject.

W pliku 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 < obiekt bazy danych > może przejść przed lub po odwzorowaniu klasy w tym samym pliku hbm.xml, co pozwala zachować definicje indeksu, wyzwalacze itp. Z obiektem, do którego się odnoszą.

Inną opcją jest 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); 
    } 
} 

Zważywszy, że używasz Fluent NHibernate, IAuxiliaryDatabaseObject prawdopodobnie będzie działać lepiej dla Ciebie. Po prostu ujawnij swoją konfigurację podczas budowania, a następnie zadzwoń:

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

N.B. NHibernate.Mapping.SimpleAuxiliaryDatabaseObject jest częścią NHibernate. Nie musisz pisać sam, jeśli wszystko, co musisz zrobić, to dostarczyć skrypty create/drop dla obiektu bazy danych.

Szybko rzuciłem okiem na bazę Fluent NHibernate i nie widziałem żadnej bezpośredniej obsługi dla IAuxiliaryDatabaseObject. Jest to więc kwestia ujawnienia obiektu konfiguracyjnego i samodzielnego dostarczania wszystkich obiektów IAuxiliaryDatabaseObjects. Nie byłoby zbyt trudno napisać kod, który skanuje twój zestaw mapujący, szukając typów, które implementują IAuxiliaryDatabaseObject, a następnie przeszukując je, aby przejść do cfg.AddAuxiliaryDatabaseObject (obj).

można znaleźć więcej informacji na temat pomocniczych obiektów bazy danych w NHibernate docs:

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

3

Myślę, że to jest niemożliwe. „FluentNHibernate.MappingModel.MappedMembers.AcceptVisitor()” iteracje właściwości przed Referencje:

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

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

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

W rezultacie, będziesz zawsze mieć właściwości przed indeksem odniesienia w wielu kolumnach.

BTW żaden z ORMs daje możliwość ustawienia nietrywialne opcji indeksowych jak skupione, sączy itp

+0

Dzięki. W takim przypadku, czy znasz sposób dołączania niestandardowego (ręcznego) schematu do konfiguracji? Wolałbym mieć wszystkie SQL związane z tworzeniem DB w jednym miejscu. Sądzę, że mógłbym po prostu wykonać zwykły SQL, aby dodać indeksy, po tym jak NHibernate zbuduje resztę schematu. – Groo

2

Pozwolę sobie zasugerować, aby zastąpić SchemaExport. Istnieje prywatny dostęp do pola poprzez odbicie, wymaga trybu pełnego zaufania. Jeśli takie podejście nie pasuje do Twoich potrzeb, należy rozważyć przepisanie SchemaExport (klasa stosunkowo lekki)


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

Dzięki, niezła sugestia. Kilka uwag jednak: a) Myślę, że twoje ogólne nawiasy zostały zgubione '<>', b) 'createSQL' wydaje się zwracać tablicę ciągów w FluentHib. 1.1, c) w rzeczywistości nigdy nie sortujesz atrybutów według numeru indeksu, d) lista 'fields' nie będzie poprawnie renderowana przez siebie, w' sb.AppendLine'. Mogę to łatwo naprawić, ale wolałbym raczej mieć indeksy w moich klasach odwzorowania niż w rzeczywistych jednostkach, więc prawdopodobnie przepisałbym je w dużej części, aby przenieść je tam. Mimo to odpowiedziałeś na moje pytanie i wpadłeś na dobry pomysł. – Groo

Powiązane problemy