Multi-column IUserType fails in SubclassMap<> #210

Closed
matthewpeckterremark opened this Issue Feb 21, 2013 · 7 comments

Comments

Projects
None yet
3 participants

When mapping a subclass entity property with a custom IUserType that takes multiple columns, the resulting Configuration contains a property mapping specification including only the first provided column. Converting the subclass entity to a root class and using the exact same IUserType results in no issue. Something that occurs during the application of the IIndeterminateSubclassMappingProvider is dropping all columns after the first.

Collaborator

chester89 commented Feb 22, 2013

I would appreciate if you post your mappings and entities so I could investigate

Fluent code built from jagregory-fluent-nhibernate-d3232ef as of 2012/07/20. By the time the configuration process gets to the end of the try block in FluentConfiguration.BuildConfiguration() (line 260 of FluentNHibernate.Cfg.FluentConfiguration.cs in the version I built from), the only column listed in the Contexts property mapping is "IsIcon", even though ColumnMappingCollection.Add(string) executed for all four columns specified in the ImageMap class, and the mapping definition prior to the end of BuildConfiguration() listed all four columns specified. I haven't had time to chase down exactly where the problem occurs.

Entities, mappings, and IUserType below, trimmed-down to eliminate excess clutter. "Entity" is an abstract base class with no implementation. Inheriting Image directly from Entity, adding the Id property and mapping to it, and converting the mapping to a ClassMap, the symptoms disappear, and the Contexts collection is filled as expected.

public class Media : Entity
{

    public virtual Guid Id { get; protected set; }
    public virtual bool IsDeprecated { get; set; }
    public virtual DateTime Created { get; set; }
    public virtual DateTime Modified { get; set; }

}

public class MediaMap : ClassMap<Media>
{
    public MediaMap()
    {
        Id(x => x.Id).Column("[Guid]").GeneratedBy.GuidComb();
        Map(x => x.IsDeprecated).Not.Nullable();
        Map(x => x.Created).Not.Nullable();
        Map(x => x.Modified).Not.Nullable();
    }
}

public class Image : Media
{
    private IList<string> contexts = new List<string>();

    public virtual string Title { get; set; }
    public virtual string Description { get; set; }
    public virtual int Width { get; set; }
    public virtual int Height { get; set; }

    public virtual IList<string> Contexts { get { return contexts; } }
}

public class ImageMap : SubclassMap<Image>
{
    public ImageMap()
    {
        Table("[ImageInfo]");
        KeyColumn("[Guid]");
        Map(x => x.Title).Length(100).Not.Nullable();
        Map(x => x.Description).Length(500).Nullable();
        Map(x => x.Width).Not.Nullable();
        Map(x => x.Height).Not.Nullable();
        Map(x => x.Contexts)
            .Access.CamelCaseField()
            .CustomType<ImageContextsUserType>()
            .Columns.Add(new [] {"IsIcon", "IsPromo", "IsWallpaper", "IsPlaceholder"})
            .Not.Nullable();
    }
}

public class ImageContextsUserType : IUserType
{
    public object NullSafeGet(IDataReader rs, string[] names, object owner)
    {
        IList<string> contexts = new List<string>();

        if ((bool)NHibernateUtil.Boolean.NullSafeGet(rs, names[0])) contexts.Add("Icon");
        if ((bool)NHibernateUtil.Boolean.NullSafeGet(rs, names[1])) contexts.Add("Promo");
        if ((bool)NHibernateUtil.Boolean.NullSafeGet(rs, names[2])) contexts.Add("Wallpaper");
        if ((bool)NHibernateUtil.Boolean.NullSafeGet(rs, names[3])) contexts.Add("Placeholder");

        return contexts;
    }

    public void NullSafeSet(IDbCommand cmd, object value, int index)
    {
        IList<string> contexts = value as IList<string>;

        if (contexts != null)
        {
            NHibernateUtil.Boolean.NullSafeSet(cmd, contexts.Contains("Icon"), index);
            NHibernateUtil.Boolean.NullSafeSet(cmd, contexts.Contains("Promo"), index + 1);
            NHibernateUtil.Boolean.NullSafeSet(cmd, contexts.Contains("Wallpaper"), index + 2);
            NHibernateUtil.Boolean.NullSafeSet(cmd, contexts.Contains("Placeholder"), index + 3);
        }
    }

    public Type ReturnedType
    {
        get { return typeof(IList<string>); }
    }

    public SqlType[] SqlTypes
    {
        get
        {
            return new [] {
                NHibernateUtil.Boolean.SqlType, NHibernateUtil.Boolean.SqlType,
                NHibernateUtil.Boolean.SqlType, NHibernateUtil.Boolean.SqlType };
        }
    }
}
Collaborator

chester89 commented Jul 23, 2013

Well, that's really weird - I just repeated your setup, and resulted hbm xml contains all the columns of a user type.
Here's the relevant part: https://gist.github.com/chester89/6066142
I assume it's correct, or am I missing something?

gliljas commented Sep 30, 2013

I can confirm that it fails in the Nuget version, but works in "the trunk". The error did not occur with NH 3.1 and FNH 1.2.0.712.

Collaborator

chester89 commented Sep 30, 2013

By trunk you mean the current master branch?

2013/9/30 gliljas notifications@github.com

I can confirm that it fails in the Nuget version, but works in "the
trunk". The error did not occur with NH 3.1 and FNH 1.2.0.712.

Reply to this email directly or view it on GitHubhttps://github.com/jagregory/fluent-nhibernate/issues/210#issuecomment-25374000
.

ó Õ×ÁÖÅÎÉÅÍ,
þÅÒÍ£ÎÎÏ× çÌÅÂ,
ÔÅÌ. (916) 314-9324

gliljas commented Sep 30, 2013

Yes

Collaborator

chester89 commented Sep 30, 2013

Ok, then I'd write a test and the issue is resolved, I guess.

2013/9/30 gliljas notifications@github.com

Yes

Reply to this email directly or view it on GitHubhttps://github.com/jagregory/fluent-nhibernate/issues/210#issuecomment-25375966
.

ó Õ×ÁÖÅÎÉÅÍ,
þÅÒÍ£ÎÎÏ× çÌÅÂ,
ÔÅÌ. (916) 314-9324

chester89 added a commit that referenced this issue Nov 13, 2013

Merge pull request #249 from chester89/issue210
#210 - Multi-column IUserType fails in SubclassMap<>

@chester89 chester89 closed this Nov 13, 2013

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment