Как переименовать столбец компонента, который является внешним ключом? - PullRequest
2 голосов
/ 11 августа 2011

Мы используем fluentnhibernate с автоматическим отображением, и у нас есть соглашение об именах, согласно которому для всех столбцов, которые являются внешними ключами, имя столбца заканчивается на «Ключ». Итак, у нас есть соглашение, которое выглядит так:

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

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

Это прекрасно работает, пока мы не создадим компонент, в котором одно из его значений является внешним ключом. Переименовывая столбец здесь, он переопределяет имя по умолчанию, данное столбцу компонента, который включает в себя ComponentPrefix, определенный в AutomappingConfiguration. Есть ли способ для меня получить ComponentPrefix в этом соглашении? или есть какой-то другой способ для меня получить имя столбца для компонентов со свойством, которое является внешним ключом и заканчивается словом «Ключ»?

Ответы [ 2 ]

1 голос
/ 15 августа 2013

После долгих хлопот, проб и ошибок (таким образом, соблазнившись использовать ваше решение с Reflection), я пришел к следующему:

Этот метод зависит от порядка выполнения соглашений.Этот условный порядок происходит через строгую иерархию.В этом примере сначала обрабатывается условное обозначение компонента (IDynamicComponentConvention), а затем обрабатываются условные обозначения внутренних свойств, например отображение ссылок (IReferenceConvention).

В строгом порядке мы делаем наш забастовку:

  1. Мы собираем правильное имя столбца при вызове Apply(IDynamicComponentConvention instance), помещаем его в очередь. Обратите внимание, что используется Queue<T>, который является типом коллекции FIFO (первым пришел-первым вышел), поэтому он правильно сохраняет порядок.

  2. Почти сразупосле этого Apply(IManyToOneInstanceinstance) вызывается.Мы проверяем, есть ли что-нибудь в очереди.Если есть, мы вынимаем его из очереди и устанавливаем как имя столбца. Обратите внимание, что вы не должны использовать Peek() вместо Dequeue(), поскольку он не удаляет объект из очереди.

Код выглядит следующим образом:

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!
    }
}
0 голосов
/ 12 августа 2011

Я нашел способ сделать это, используя отражение, чтобы добраться до основного отображения IManyToOneInspector, предоставляемого IComponentInstance, но надеялся, что есть лучший способ сделать это?

Вот пример кода того, как я достиг этого:

#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; 
    } 
} 
...