NHibernate:无法在实体的构造函数中分配属性值 [英] NHibernate: Cannot assign property value in entity's constructor

查看:92
本文介绍了NHibernate:无法在实体的构造函数中分配属性值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我在B的构造函数中运行以下代码时,我得到了NullReferenceException.我无法为B的Number属性分配值.

When I run the following code, at B's constructor, I got a NullReferenceException. I cannot assign value to B's Number property.

型号:

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.

I'm using NHibernate 3.1.0.4000, FluentNHibernate 1.2.0.712.

有什么想法吗?谢谢.

推荐答案

关键是Number是虚拟的.

A.B正在延迟加载. NHibernate为B创建一个代理,该代理将覆盖该类中的每个虚拟属性.第一次访问非Id属性之一时,NHibernate将从数据库中加载数据以填充对象.

A.B is being lazy-loaded. NHibernate creates a proxy for B which overrides each virtual property in the class. The first time one of the non-Id properties is accessed, NHibernate will load the data from the database to populate the object.

由于此代理类是B的子类,因此将在代理构造函数之前调用B的构造函数.当B的构造函数设置虚拟属性Number时,它将调用尚未初始化的代理子类中定义的Number属性.

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

有关构造函数和继承的更详尽讨论,请参见 http://www.yoda .arachsys.com/csharp/constructors.html

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

要解决此问题,请将希望在构造函数中设置的所有属性转换为使用后备字段而不是自动属性,然后在构造函数中设置字段而不是属性.

To fix this, convert any properties you wish to set in the constructor to use backing fields instead of auto-properties, then set the 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; }
    }
}

这有点冗长,但可以有效避免在构造函数中接触虚拟方法或属性.

It's a bit more verbose, but it effectively avoids touching virtual methods or properties in the constructor.

这篇关于NHibernate:无法在实体的构造函数中分配属性值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆