Search code examples
nhibernatefluent-nhibernatefluent-nhibernate-mappingautomapping

FluentNHibernate: Id Column Name Ignored


FluentNHibernate: 1.3.0.733
NHibernate: 3.3.1.4000

I'm trying to set the column name of the Id column, but it seems to be ignored.


Edit:
Found solution. Property redeclaration (new-modifier) was the problem (see answer).


I'm using AutoMapping with conventions and overrides.

Override:

public class OrderHeadMapping : IAutoMappingOverride<OrderHead>
{
    public void Override(AutoMapping<OrderHead> mapping)
    {
        mapping.Schema("[database].[dbo]");
        mapping.Table("OrderHeads");            

        mapping.Id(x => x.Id, "desiredColumnName")              
            .Column("desiredColumnName")
            .GeneratedBy.UuidString();
        ...
    }
}

This code gets executed, but the column name stays "Id".

I've already exported the mappings to an directory to see what's the outcome:

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
  <class xmlns="urn:nhibernate-mapping-2.2" schema="[database].[dbo]" name="OrderHead, Core, Version=1.0.4666.19686, Culture=neutral, PublicKeyToken=null" table="OrderHeads">
    <cache usage="read-write" />
    <id name="Id" type="System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      <column name="Id" />
      <generator class="assigned" />
    </id>
    ...
  </class>
</hibernate-mapping>

I've searched my whole solution for ".Id(" and ".Column(" to ensure it is not accidently reset but none of the results deal with setting/overwriting the id column name. So now I'm a little bit lost.


Solution

  • I finally found the problem:
    One thing I left out in my description is that I have two base entities:

    public abstract class Entity
    {
        protected object _id;
    
        public virtual object Id
        {
            get { return _id; }
            protected internal set { _id = value; }
        }
    }
    
    public abstract class Entity<TKey> : Entity
    {
        public Entity()
        {
            _id = default(TKey);
        }
        new public virtual TKey Id 
        {
            get { return (TKey)_id; }
            protected internal set { _id = (TKey)value; } 
        }
        ...
    }
    

    The problem was that FluentNHibernate handles redefined properties twice: Entity.Id and Entity<>.Id ultimately overwriting the desired mapping with the mapping of the base class version. So I have to walk the inheritance tree up to check if this member is the top most rewrite (if any).

    Now I handle the problem in the ShouldMap method in my implementation of DefaultAutomappingConfiguration:

    public override bool ShouldMap(Member member)
    {
        var res = base.ShouldMap(member);
    
        if (res == true)                
        {
            var originalDeclaringType = GetOriginalDeclaringType(member.MemberInfo);
            ...
            if(member.Name == "Id")
            {
                if (GetTopMostRedefinedMember(member.MemberInfo) != member.MemberInfo.DeclaringType)
                    return false;
            }
        }           
        ...
        return res;
    }
    

    with GetTopMostRedefinedMember being:

    private Type GetTopMostRedefinedMember(MemberInfo member)
        {
            List<Type> types = new List<Type>();
    
            Type type = member.ReflectedType;
            while (type != null)
            {
                types.Add(type);
                type = type.BaseType;
            }
    
            foreach (var t in types)
            {
                var tmp = t.GetMember(member.Name, BindingFlags.Public |
                          BindingFlags.NonPublic |
                          BindingFlags.Instance |
                          BindingFlags.DeclaredOnly);
                if (tmp.Length != 0)
                {
                    type = t;
                    break;
                }
            }
            return type;
        }
    

    Disclaimer: This code is not thoroughly tested.

    I hope someday someone will be safed from debugging hours!

    Lg
    warappa