2011-08-11 1 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"); 
    } 
} 

이것은 값 중 하나가 외래 키인 구성 요소를 만들 때까지 훌륭하게 작동합니다. 여기에서 열 이름을 바꾸면 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! 
    } 
}