NHibernate: cannot assign property value in entity constructor

When I run the following code, in constructor B, I get a NullReferenceException. I cannot assign a value to the B Number property.

Models:

public class A { public A() { this.Number = 1; if (this.Number != 1) { throw new Exception("Failed to assign value in A constructor"); } } public virtual int Id { get; private set; } public virtual int Number { get; set; } public virtual BB { get; set; } } public class B { public B() { this.Number = 1; // Throws NullReferenceException: Object reference not set to an instance of an object. if (this.Number != 1) { throw new Exception("Failed to assign value in B constructor"); } } public virtual int Id { get; private set; } public virtual int Number { get; set; } } 

Mapping:

 public class AMappings : ClassMap<A> { public AMappings() { Id(x => x.Id); Map(x => x.Number); References(x => xB).Cascade.All(); } } public class BMappings : ClassMap<B> { public BMappings() { Id(x => x.Id); Map(x => x.Number); } } 

The main method:

 class Program { static void Main(string[] args) { // Create connection string string connectionString = new System.Data.SqlClient.SqlConnectionStringBuilder() { DataSource = @".\r2", InitialCatalog = "TestNHibernateMappings", IntegratedSecurity = true }.ConnectionString; // Create SessionFactory ISessionFactory sessionFactory = Fluently.Configure() .Database(MsSqlConfiguration .MsSql2008.ConnectionString(connectionString) .ShowSql()) .Mappings(m => m.FluentMappings .Add(typeof(AMappings)) .Add(typeof(BMappings))) .ExposeConfiguration(BuildSchema) .BuildConfiguration() .BuildSessionFactory(); // Create test object in DB using (var session = sessionFactory.OpenSession()) { using (var trans = session.BeginTransaction()) { var a = new A(); aB = new B(); session.Save(a); trans.Commit(); } } // Read test object from DB using (var session = sessionFactory.OpenSession()) { using (var trans = session.BeginTransaction()) { var a = session.Get<A>(1); } } } static void BuildSchema(Configuration cfg) { new SchemaExport(cfg).Create(false, true); } } 

I am using NHibernate 3.1.0.4000, FluentNHibernate 1.2.0.712.

Any ideas? Thanks.

0
source share
1 answer

The key here is that Number is virtual.

AB loads lazily. NHibernate creates a proxy for B , which overrides every virtual property in the class. When you first access one of the non- Id properties, NHibernate will load data from the database to populate the object.

Since this proxy class is a subclass of B , constructor B will be called before the proxy constructor. When constructor B sets the virtual Number property, it calls the Number property, as defined in a proxy subclass that has not yet been initialized.

For a more detailed discussion of constructors and inheritance, see http://www.yoda.arachsys.com/csharp/constructors.html

To fix this, convert any properties that you want to set in the constructor to use support fields instead of automatic properties, and then set this field instead of the property in the constructor.

 public class B { public B() { _number = 1; } public virtual int Id { get; private set; } private int _number; public virtual int Number { get { return _number; } set { _number = value; } } } 

This is a bit more verbose, but it effectively avoids touching virtual methods or properties in the constructor.

+3
source

All Articles