Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

Already on GitHub? Sign in to your account

IgnoreProperty does not ignore overridden properties in sub-classes #109

Open
chilversc opened this Issue Nov 11, 2011 · 3 comments

Comments

Projects
None yet
3 participants

mapping.IgnoreProperty (x => x.IsOverriden) does not ignore properties that are overriden in sub-classes.
Further more, it cannot ignore properties that are overriden in sub-classes.

Eg

    public class ItemBase { public virtual bool IsOverriden { get { return false; } } }
    public class Item : ItemBase { public override bool IsOverriden { get { return true; } } }

This partially works, it will ignore ItemBase.IsOverriden but not Item.IsOverriden

    public void Override (AutoMapping<ItemBase> mapping) {
        mapping.IgnoreProperty (x => x.IsOverriden);
    }

This does not work, Item.IsOverriden will not be ignored.

    public void Override (AutoMapping<Item> mapping) {
        // This does not work, it will not ignore Item.IsOverriden
        mapping.IgnoreProperty (x => x.IsOverriden);
    }

As a work around the following does work:

    public void Override (AutoMapping<Item> mapping) {
        mapping.IgnoreProperty (Reveal.Member<Item> ("IsOverriden"));
    }

The following example reproduces the error with FNH 1.3.0.717 and earlier: https://gist.github.com/1358583

// uses NHibernate 3.2.0.4000
// uses FluentNHibernate 1.3.0.717

namespace ConsoleApplication1
{
    using System;
    using System.IO;
    using FluentNHibernate;
    using FluentNHibernate.Automapping;
    using FluentNHibernate.Automapping.Alterations;
    using FluentNHibernate.Cfg;
    using FluentNHibernate.Cfg.Db;

    public class Program
    {
        public static void Main()
        {
            var cfg = new AutoMappingConfiguration ();
            var mapping = AutoMap
                .AssemblyOf<AutoMappingConfiguration> (cfg)
                .UseOverridesFromAssemblyOf<AutoMappingConfiguration> ()
                .Conventions.AddFromAssemblyOf<AutoMappingConfiguration> ();

            using (var file = File.CreateText ("mapping.xml"))
                Fluently.Configure ()
                    .Database (SQLiteConfiguration.Standard.InMemory)
                    .ProxyFactoryFactory<NHibernate.Bytecode.DefaultProxyFactoryFactory> ()
                    .Mappings (m => m.AutoMappings.Add (mapping).ExportTo (file))
                    .BuildConfiguration ();
        }
    }

    public class AutoMappingConfiguration : DefaultAutomappingConfiguration
    {
        public override bool ShouldMap(Type type)
        {
            return type == typeof (ItemBase) || type == typeof (Item);
        }
    }

    public class ItemBaseOverride : IAutoMappingOverride<ItemBase>
    {
        public void Override (AutoMapping<ItemBase> mapping)
        {
            mapping.IgnoreProperty (x => x.IsOverriden);
        }
    }

    public class ItemOverride : IAutoMappingOverride<Item>
    {
        public void Override (AutoMapping<Item> mapping)
        {
            // Fails:
            mapping.IgnoreProperty (x => x.IsOverriden);

            // Works:
            //mapping.IgnoreProperty (Reveal.Member<Item> ("IsOverriden"));
        }
    }

    public class ItemBase
    {
        public long Id { get; set; }
        public string Name { get; set; }

        public virtual bool IsOverriden
        {
            get { return false; }
        }
    }

    public class Item : ItemBase
    {
        public override bool IsOverriden
        {
            get { return true; }
        }
    }
}

Example Result (cleaned up a little)

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
  <class xmlns="urn:nhibernate-mapping-2.2" name="ConsoleApplication1.ItemBase, ConsoleApplication1" table="`ItemBase`">
    <id name="Id">
      <generator class="identity" />
    </id>
    <property name="Name" />
    <joined-subclass name="ConsoleApplication1.Item, ConsoleApplication1">
      <key>
        <column name="ItemBase_id" />
      </key>
      <property access="property" name="IsOverriden" />
    </joined-subclass>
  </class>
</hibernate-mapping>

Ideally I think auto-mapping should ignore properties in sub-classes that are already mapped by a super-class rather than mapping the same property twice.

Cases

  1. super-class is not mapped, thus property is not mapped, sub-class must define the property.
  2. super-class is mapped, thus the property is mapped, sub-class must not define the property.
  3. super-class is mapped but property was ignored, thus property is not mapped, sub-class must define the property.
  4. super-class is mapped but property was ignored for all sub-classes, thus property is not mapped, sub-class must not define the property.

3 could be optional if 4 is always assumed. I.E. ignores are always inherited, though this would be a breaking change.
4 would require adding an extra ignore method to AutoMapping<T>, e.g. mapping.IgnorePropertyForAllSubClasses (x => x.IsOverriden)

It might also be worth while looking at how inheritance as a whole is handled rather than just ignoring properties as a similar problem occurs when declaring a super-class' abstract property as Access.ReadOnly(), you then have to ignore that property from each of the sub-classes.

Fwiw, we have the exact problem. We want our overridden property in base class and subclasses ignored. While it ignores in base class, it doesn't in subclasses.

Collaborator

chester89 commented Sep 12, 2012

I understand the problem, but I'm not sure how to approach this. Also, breaking change isn't a good idea for a minor release. If only @jagregory can give some advice

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