开发者

How to rename a component column that is a foreign key?

We are using fluentnhibernate with automapping and we have a naming convention that all columns that are foreign keys, there column name will end with "Key". So we have a convention that looks like this:

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

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

This works great until we created a component in which one of its values is a foreign key. By renaming the column here it overrides the default name given to the component column which includes the ComponentPre开发者_如何转开发fix which is defined in the AutomappingConfiguration. Is there a way for me to get the ComponentPrefix in this convention? or is there some other way for me to get the column name for components with a property that is a foreign key to end in the word "Key"?


After a lot of fiddling and trial & error (thus being tempted to use your solution with Reflection) I came up with the following:

This method depends on the order of the execution of the conventions. This convention-order happens via a strict hierarchy. In this example, at first, the convention of the component (IDynamicComponentConvention) is being handled and after that the conventions of the inner properties are being handled such as the References mapping (IReferenceConvention).

The strict order is where we make our strike:

  1. We assemble the correct name of the column in the call to Apply(IDynamicComponentConvention instance), put it on the queue. Note that a Queue<T> is used which is a FIFO (first-in-first-out) collection type thus it keeps the order correctly.

  2. Almost immediately after that, Apply(IManyToOneInstanceinstance) is called. We check if there is anything in the queue. If there is, we take it out of the queue and set it as column name. Note that you should not use Peek() instead of Dequeue() as it does not remove the object from the queue.

The code is as follows:

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


I Have figured out a way to do this using reflection to get to the underlying mapping of the IManyToOneInspector exposed by the IComponentInstance but was hoping there was a better way to do this?

Here is some example code of how I achieved this:

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

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜