NHibernate:无法在实体的构造函数中赋值属性

时间:2011-04-26 02:24:13

标签: nhibernate fluent-nhibernate

当我运行以下代码时,在B的构造函数中,我得到了一个N​​ullReferenceException。我无法为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。

有什么想法吗?感谢。

1 个答案:

答案 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; }
    }
}

它有点冗长,但它有效地避免了在构造函数中触摸虚拟方法或属性。