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

Fluent nhibernate 如何重命名作为外键的组件列?,fluent-nhibernate,components,automapping,Fluent Nhibernate,Components,Automapping,我们使用fluentnhibernate进行自动映射,我们有一个命名约定,即所有列都是外键,它们的列名将以“Key”结尾。所以我们有一个这样的惯例: public class ForeignKeyColumnNameConvention : IReferenceConvention { public void Apply ( IManyToOneInstance instance ) { // name the key field string p

我们使用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”结尾?

我已经找到了一种方法,使用反射来获取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; 
    } 
} 
#地区IConvention成员
public void Apply(IComponentInstance实例)
{ 
foreach(instance.References中的var manyToOneInspector)
{ 
var referenceName=string.Format(“{0}{1}{2}{3}”,instance.EntityType.Name,manyToOneInspector.Property.PropertyType.Name,_autoMappingConfiguration.getComponentColumnProfix(instance.Property),manyToOneInspector.Property.Name);
if(manyToneInspector.Property.PropertyType.IsSubclassOf(typeof(LookupBase)))
{ 
referenceName+=“Lkp”;
} 
manyToOneInspector.Index(string.Format(“{0}\u FK\u IDX”,referenceName));
} 
} 
#端区
公共静态类ManyToneInspectorExtensions
{ 
公共静态ManyToOneMapping GetMapping(此IManyToOneInspector manyToOneInspector)
{ 
var fieldInfo=manyToOneInspector.GetType().GetField(“映射”,BindingFlags.NonPublic | BindingFlags.Instance);
如果(fieldInfo!=null)
{ 
var manyToOneMapping=fieldInfo.GetValue(manyToOneInspector)作为manyToOneMapping;
返回多通映射;
} 
返回null;
} 
公共静态无效索引(此IManyToOneInspector MANYTONEINSPECTOR,字符串indexName)
{ 
var-mapping=manyToOneInspector.GetMapping();
mapping.Index(indexName);
} 
公共静态无效列(此IManyToOneInspector MANYTONEINSPECTOR,字符串列名称)
{ 
var-mapping=manyToOneInspector.GetMapping();
mapping.Column(columnName);
} 
公共静态void ForeignKey(此IManyToOneInspector manyToOneInspector,字符串foreignKeyName)
{ 
var-mapping=manyToOneInspector.GetMapping();
mapping.ForeignKey(foreignKeyName);
} 
} 
公共静态类ManyToneMappingExtensions
{ 
公共静态void索引(此ManyToOneMapping ManyToOneMapping,字符串indexName)
{ 
if(manyToneMapping.Columns.First().IsSpecified(“索引”))
返回;
foreach(manyToOneMapping.Columns中的var列)
{ 
column.Index=indexName;
} 
} 
公共静态void列(此ManyToOneMapping ManyToOneMapping,字符串columnName)
{ 
if(manyToneMapping.Columns.UserDefined.Count()>0)
返回;
var originalColumn=manyToneMapping.Columns.FirstOrDefault();
var column=originalColumn==null?新ColumnMapping():originalColumn.Clone();
column.Name=columnName;
manyToOneMapping.ClearColumns();
manyToOneMapping.AddColumn(column);
} 
公共静态void ForeignKey(此ManyToOneMapping ManyToOneMapping,字符串foreignKeyName)
{ 
如果(!manyToneMapping.IsSpecified(“ForeignKey”))
manyToOneMapping.ForeignKey=foreignKeyName;
} 
} 

经过大量的修改和尝试与错误(因此,我很想使用您的解决方案进行反射),我得出了以下结论:

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

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

  • 在调用
    Apply(IDynamicComponentConvention实例)
    时,我们将列的正确名称组合在一起,并将其放入队列中。请注意,使用了一个
    队列
    ,它是FIFO(先进先出)收集类型,因此它可以正确地保持顺序

  • 几乎紧接着,调用了
    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!
        }
    }
    
    公共密封类CustomNamingConvention:IDynamicComponentConvention,IReferenceConvention{
    私有静态队列ColumnNames=新队列();
    public void Apply(IDynamicComponentInstance实例){
    foreach(instance.References中的var referenceInspector){
    //我们需要的所有信息都在这里
    //但仅用于检查,尚未编辑:(
    //别担心,只需将名称组合起来并将其排队即可
    var name=string.Format(“{0}{1}”,
    实例.名称,
    referenceInspector.Columns.Single().Name);
    ColumnNames.Enqueue(名称);
    }
    }
    public void Apply(IManyToOneInstance实例){
    如果(!ColumnNames.Any())
    //队列中没有任何内容?然后返回(^ ^)
    返回;
    //将检索到的字符串设置为