如何重命名作为外键的组件列?

时间:2011-08-11 13:14:17

标签: fluent-nhibernate components 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”结尾的外键?

2 个答案:

答案 0 :(得分:1)

经过大量的摆弄和试用后错误(因此很想用反射来使用你的解决方案)我想出了以下内容:

此方法取决于约定的执行顺序。这种约定顺序通过严格的层次结构发生。在此示例中,首先,正在处理组件(IDynamicComponentConvention)的约定,然后处理内部属性的约定,例如引用映射(IReferenceConvention)。

严格的命令是我们进行罢工的地方:

  1. 我们在调用Apply(IDynamicComponentConvention instance)时汇集了列的正确名称,并将其放入队列中。 请注意,使用Queue<T>这是一个FIFO(先进先出)集合类型,因此它可以正确保存订单。

  2. 在此之后几乎立即调用Apply(IManyToOneInstanceinstance)。我们检查队列中是否有任何内容。如果有,我们将其从队列中取出并将其设置为列名。 请注意,您不应使用Peek()而不是Dequeue(),因为它不会从队列中删除对象。

  3. 代码如下:

    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!
        }
    }
    

答案 1 :(得分: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; 
    } 
}