Search code examples
c#sqlitenhibernatefluent-nhibernate

Excluding private fields with fluent nhibernate


I am looking to retrofit a database to an existing codebase with as little pain as possible using NHibernate and an sqlite database. I would like to go about this by using the AutoMapper to map the fields that I tag with a [DatabaseField] custom attribute for any object that inherits from a custom DatabaseObject class. Anything marked with a [Cascade] custom attribute will be cascaded. I have the following code in a test project at the moment:

Entities to map:

   class Scan : DatabaseObject
    {    
        [DatabaseField]
        public virtual string Name { get; set; }
        [DatabaseField]
        public virtual DateTime ScanDate { get; set; }
        [DatabaseField]
        [Cascade]
        public virtual Scanner Scanner { get; set; }

        public DateTime ManufactureDate { get; set; }
    }

    class Scanner : DatabaseObject
    {
        [DatabaseField]
        public virtual string Name { get; set; }
    }

Session setup:

    ProjectConfiguration pcfg = new ProjectConfiguration();



 var sessionFactory = Fluently.Configure()
        .Database(SQLiteConfiguration.Standard.UsingFile("theTestScannerDatabase.sqlite"))
        .Mappings(m => m.AutoMappings.Add(AutoMap.AssemblyOf<Scan>(pcfg)
        .Override<Scan>(x => x.IgnoreProperty(y => y.ManufactureDate)).Conventions.Setup(x => x.AddFromAssemblyOf<Scan>())))
        .ExposeConfiguration(BuildSchema)
        .BuildSessionFactory();
    return sessionFactory.OpenSession();

Project Configuration object

public class ProjectConfiguration : DefaultAutomappingConfiguration
{
    public override bool ShouldMap(Type type)
    {
        return type.BaseType == typeof(DatabaseObject);
    }

    public override bool ShouldMap(Member member)
    {
        return member.MemberInfo.GetCustomAttributes().Contains(new DatabaseField());
    }

}

The problem is with the "ManufactureDate" field which the automapper has tried to map and is upset that it isn't a virtual property, and similar things happen with private properties. I don't want to map every property of my objects to the database. I thought that the tags and the stuff in the ShouldMap overrides should take care of this.

The exception:

InvalidProxyTypeException: The following types may not be used as proxies:
SQLiteTestingApp.Scan: method get_ManufactureDate should be 'public/protected virtual' or 'protected internal virtual'
SQLiteTestingApp.Scan: method set_ManufactureDate should be 'public/protected virtual' or 'protected internal virtual'

For the record, if I remove this field everything else maps exactly how I want it to.

I have read about the Override and OverrideAll methods that I've tried to use to explicitly exclude these fields, but it doesn't seem to have any effect. I left an example of this attempt in my code snippet above.

So I guess I have two questions:

  • How can I tell the automapper to ignore anything I don't tag with my attribute?
  • If this isn't possible, what is the easiest way to map my existing objects to a database without creating a mapping class for every object I want to map?

Thanks in advance


Solution

  • Take a look at the documentation for ignoring properties.

    You can use the IgnoreProperty method.

    .Override<Scan>(map =>  
    {  
      map.IgnoreProperty(x => x.ManufactureDate);
    });
    

    All properties/methods in an entity also need to be virtual or implement an interface as per documentation for persistent classes.

    A central feature of NHibernate, proxies, depends upon the persistent class being non-sealed and all its public methods, properties and events declared as virtual. Another possibility is for the class to implement an interface that declares all public members.