2011-08-11 15 views
2

私たちはautomappingでfluentnhibernateを使用しています。私たちは、外部キーであるすべてのカラム、カラム名が "Key"で終わる命名規則を持っています。したがって、次のような規則があります。外部キーであるコンポーネント列の名前を変更する方法は?

public class ForeignKeyColumnNameConvention : IReferenceConvention 
{ 
    public void Apply (IManyToOneInstance instance) 
    { 
     // name the key field 
     string propertyName = instance.Property.Name; 

     instance.Column (propertyName + "Key"); 
    } 
} 

これは、その値の1つが外部キーであるコンポーネントを作成するまで有効です。ここで列の名前を変更すると、AutomappingConfigurationで定義されたComponentPrefixを含むコンポーネント列に与えられたデフォルト名が上書きされます。このコンベンションでComponentPrefixを入手する方法はありますか?または「Key」という単語で終わる外来キーであるプロパティを持つコンポーネントの列名を取得するための他の方法がありますか?

答えて

0

私はIComponentInstanceによって公開されているIManyToOneInspectorの基本的なマッピングにリフレクションを使用してこれを行う方法を考え出しましたが、これを行うためのよりよい方法が必要だったと思いますか?私は、次のを思い付いた(これリフレクションを使用してソリューションを使用するように誘惑されている)いじると裁判&エラーの多くの後

#region IConvention<IComponentInspector, IComponentInstance> Members 
    public void Apply(IComponentInstance instance) 
    { 
     foreach (var manyToOneInspector in instance.References) 
     { 
      var referenceName = string.Format("{0}_{1}_{2}{3}", instance.EntityType.Name, manyToOneInspector.Property.PropertyType.Name, _autoMappingConfiguration.GetComponentColumnPrefix(instance.Property), manyToOneInspector.Property.Name); 
      if(manyToOneInspector.Property.PropertyType.IsSubclassOf(typeof(LookupBase))) 
      { 
       referenceName += "Lkp"; 
      } 
      manyToOneInspector.Index (string.Format ("{0}_FK_IDX", referenceName)); 
     } 
    } 
#endregion 
public static class ManyToOneInspectorExtensions 
{ 
    public static ManyToOneMapping GetMapping(this IManyToOneInspector manyToOneInspector) 
    { 
     var fieldInfo = manyToOneInspector.GetType().GetField("mapping", BindingFlags.NonPublic | BindingFlags.Instance); 
     if (fieldInfo != null) 
     { 
      var manyToOneMapping = fieldInfo.GetValue(manyToOneInspector) as ManyToOneMapping; 
      return manyToOneMapping; 
     } 
     return null; 
    } 
    public static void Index(this IManyToOneInspector manyToOneInspector, string indexName) 
    { 
     var mapping = manyToOneInspector.GetMapping(); 
     mapping.Index (indexName); 
    } 
    public static void Column(this IManyToOneInspector manyToOneInspector, string columnName) 
    { 
     var mapping = manyToOneInspector.GetMapping(); 
     mapping.Column (columnName); 
    } 
    public static void ForeignKey(this IManyToOneInspector manyToOneInspector, string foreignKeyName) 
    { 
     var mapping = manyToOneInspector.GetMapping(); 
     mapping.ForeignKey (foreignKeyName); 
    } 
} 
public static class ManyToOneMappingExtensions 
{ 
    public static void Index (this ManyToOneMapping manyToOneMapping, string indexName) 
    { 
     if (manyToOneMapping.Columns.First().IsSpecified("Index")) 
      return; 
     foreach (var column in manyToOneMapping.Columns) 
     { 
      column.Index = indexName; 
     } 
    } 
    public static void Column(this ManyToOneMapping manyToOneMapping, string columnName) 
    { 
     if (manyToOneMapping.Columns.UserDefined.Count() > 0) 
      return; 
     var originalColumn = manyToOneMapping.Columns.FirstOrDefault(); 
     var column = originalColumn == null ? new ColumnMapping() : originalColumn.Clone(); 
     column.Name = columnName; 
     manyToOneMapping.ClearColumns(); 
     manyToOneMapping.AddColumn(column); 
    } 
    public static void ForeignKey(this ManyToOneMapping manyToOneMapping, string foreignKeyName) 
    { 
     if (!manyToOneMapping.IsSpecified("ForeignKey")) 
      manyToOneMapping.ForeignKey = foreignKeyName; 
    } 
} 
1

:ここ

は、私はこれを達成する方法のいくつかのサンプルコードです

この方法は、規則の実行順序によって異なります。この規約は、厳密な階層を介して行われます。この例では、最初にコンポーネントの慣例(IDynamicComponentConvention)が処理されており、その後、参照プロパティマッピング(IReferenceConvention)などの内部プロパティの規則が処理されています。

  1. 我々は、Apply(IDynamicComponentConvention instance)への呼び出し内の列の正しい名前を組み立てるキューにそれを置く:

    厳密な順序

    は、我々のストライキをする場所です。 FIFO(先入れ先出し)収集タイプであるため、順序を正しく保持するQueue<T>が使用されています。

  2. ほとんど直後、Apply(IManyToOneInstanceinstance)が呼び出されます。待ち行列に何かがあるかどうか確認します。存在する場合は、キューから取り出して列名として設定します。 Dequeue()の代わりにPeek()を使用しないでください。キューからオブジェクトが削除されないためです。

コードは以下の通りである:

public sealed class CustomNamingConvention : IDynamicComponentConvention, IReferenceConvention { 
    private static Queue<string> ColumnNames = new Queue<string>(); 

    public void Apply(IDynamicComponentInstance instance) { 
     foreach (var referenceInspector in instance.References) { 
      // All the information we need is right here 
      // But only to inspect, no editing yet :(
      // Don't worry, just assemble the name and enqueue it 
      var name = string.Format("{0}_{1}", 
       instance.Name, 
       referenceInspector.Columns.Single().Name); 
      ColumnNames.Enqueue(name); 
     } 
    } 

    public void Apply(IManyToOneInstance instance) { 
     if (!ColumnNames.Any()) 
      // Nothing in the queue? Just return then (^_^) 
      return; 

     // Set the retrieved string as the column name 
     var columnName = ColumnNames.Dequeue(); 
     instance.Column(columnName); 

     // Pick a beer and celebrate the correct naming! 
    } 
} 
関連する問題