Search code examples
c#nhibernatefluent-nhibernatenhibernate-mappingfluent-nhibernate-mapping

collection of value object mapping error


I'm trying To map object field in fluent-Nhibernate and C#,the model contain an entity which has a reference field to a ValueObject,

this is the entity class

public class QueryLeaf : Entity
{
    public QueryLeaf()
    {
        FilterDescriptors = new List<FilterDescriptor>();
    }
    public virtual int Id { get; set; }
    public virtual List<FilterDescriptor> FilterDescriptors { get; set; }
}

this is the value object class

[Serializable]
public class FilterDescriptor : ValueObject
{
    public FilterOperator FilterOperator { get; set; }//this is an enum value
    public object Value { get; set; }
} 

and this is the mapping class

public sealed class QueryLeafMap : ClassMap<QueryLeaf>
{
    public QueryLeafMap()
    {
        Id(x => x.Id);    
        HasMany(x => x.FilterDescriptors).Component(com =>
        {
            com.Map(y => y.FilterOperator);
            com.Map(y => y.Value);
        });
    }
}

When running the above code the compiler stops on global.asax page and give me this error

collection element mapping has wrong number of columns QueryLeaf.FilterDescriptors type: component[FilterOperator,Value]


Solution

  • In general we can map Reference types with .References() and Value types with a .Map(). The object is for sure reference type, and is causing this kind of problem.

    In fact, we cannot map object, it is too genaral. We should create some custom type (class) or map a general value to its serialized or, if possible, to string value.

    So this small change would make the above code working:

    [Serializable]
    public class FilterDescriptor : ValueObject
    {
        public FilterOperator FilterOperator { get; set; }//this is an enum value
        // cannot map object
        // public object Value { get; set; }
        public string StringValue { get; set; }
        // and we can do some magic later
        public object Value { get { ... use the StringValue } ... }
    } 
    

    And because we used different name this should be the new mapping

    HasMany(x => x.FilterDescriptors).Component(com =>
    {
        com.Map(y => y.FilterOperator);
        //com.Map(y => y.Value);
        com.Map(y => y.StringValue);
    });