当我运行以下代码时,在B的构造函数中,我得到了一个NullReferenceException。我无法为B的Number属性赋值。
型号:
public class A
{
public A()
{
this.Number = 1;
if (this.Number != 1)
{
throw new Exception("Failed to assign value in A's constructor");
}
}
public virtual int Id { get; private set; }
public virtual int Number { get; set; }
public virtual B B { 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's constructor");
}
}
public virtual int Id { get; private set; }
public virtual int Number { get; set; }
}
映射:
public class AMappings : ClassMap<A>
{
public AMappings()
{
Id(x => x.Id);
Map(x => x.Number);
References(x => x.B).Cascade.All();
}
}
public class BMappings : ClassMap<B>
{
public BMappings()
{
Id(x => x.Id);
Map(x => x.Number);
}
}
主要方法:
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();
a.B = 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);
}
}
我正在使用NHibernate 3.1.0.4000,FluentNHibernate 1.2.0.712。
有什么想法吗?感谢。
答案 0 :(得分:3)
这里的关键是Number
是虚拟的。
A.B
正在加载延迟。 NHibernate为B
创建一个代理,它覆盖了类中的每个虚拟属性。第一次访问其中一个非Id
属性时,NHibernate将从数据库加载数据以填充该对象。
由于此代理类是B
的子类,因此将在代理构造函数之前调用B
的构造函数。当B
的构造函数设置虚拟属性Number
时,它正在调用代理子类中定义的Number
属性,该属性尚未初始化。
有关构造函数和继承的更全面讨论,请参阅http://www.yoda.arachsys.com/csharp/constructors.html
要解决此问题,请将您希望在构造函数中设置的任何属性转换为使用支持字段而不是自动属性,然后在构造函数中设置字段而不是属性。
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; }
}
}
它有点冗长,但它有效地避免了在构造函数中触摸虚拟方法或属性。