Question

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.

Était-ce utile?

La 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

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top