Search code examples
c#nhibernateormfluent-nhibernate

FluentNHibernate Exception: "Property mapping has wrong number of columns" on composite user type


I'm trying to map a Set of Entities in my domain model to a comma delimited string of ids in my database. I have written a composite user type to take care of this for me:

       public class CustomerSetToCommaString : ICompositeUserType
{
    public object GetPropertyValue(object component, int property)
    {
        throw new NotImplementedException();
    }

    public void SetPropertyValue(object component, int property, object value)
    {
        throw new NotImplementedException();
    }

    public bool Equals(object x, object y)
    {
        var set1 = x as ISet<Customer>;
        var set2 = x as ISet<Customer>;

        return (x == null) ? y == null : set1.SetEquals(set2);
    }

    public int GetHashCode(object x)
    {
        var set = x as ISet<Customer>;
        unchecked
        {
            return set == null ? 0 : set.Sum(relatie => relatie.GetHashCode());
        }
    }

    public object NullSafeGet(DbDataReader dr, string[] names, ISessionImplementor session, object owner)
    {
        var str = (string)NHibernateUtil.String.Get(dr, names[0], session);
        IList<int> ids = str.Split(',').Select(id => int.Parse(id.Trim())).ToList();
        return ((ISession) session).QueryOver<Customer>().WhereRestrictionOn(customer => customer.Id).IsInG(ids).List()
            .ToHashSet();
    }

    public void NullSafeSet(DbCommand cmd, object value, int index, bool[] settable, ISessionImplementor session)
    {
        var set = value as ISet<Customer>;
        NHibernateUtil.String.Set(cmd, string.Join(", ", set.Select(customer => customer.Id.ToString()).ToArray()), index, session);
    }

    public object DeepCopy(object value)
    {
        return ((ISet<Customer>) value).ToHashSet();
    }

    public object Disassemble(object value, ISessionImplementor session)
    {
        return DeepCopy(value);
    }

    public object Assemble(object cached, ISessionImplementor session, object owner)
    {
        return DeepCopy(cached);
    }

    public object Replace(object original, object target, ISessionImplementor session, object owner)
    {
        return original;
    }

    public string[] PropertyNames => new string[0];
    public IType[] PropertyTypes  => new IType[0];
    public Type ReturnedClass => typeof(ISet<Customer>);
    public bool IsMutable => true;
}

However when trying to map it using Map(x => x.Customers).CustomType<CustomerSetToCommaString>.Column("Customers"); I get the exception that the property mapping has the wrong number of columns. Shouldn't it try to map to a single column? Am I missing something?


Solution

  • After a frustrating day of debugging and Googleing I found the answer. The problem lies in this line:

    public IType[] PropertyTypes  => new IType[0];
    

    This specifies the column(s) which need to be filled. When I changed it to:

    public IType[] PropertyTypes  => new IType[1]{NHibernateUtil.String};
    

    I specified that the column was a single string and this solved the problem.