开发者

Problem loading an object with 2 properties of the same class with NHibernate after saving from previous session

开发者 https://www.devze.com 2023-04-04 09:00 出处:网络
I have a Device class that I have defined that has 2 properties, LocalConnection and Connection, that are of the same defined class, Connection.

I have a Device class that I have defined that has 2 properties, LocalConnection and Connection, that are of the same defined class, Connection.

Here is the Device class:

[ComVisible(true)]
[TypeConverter(typeof(ExpandableObjectConverter))]
public class Device
{
    #region Fields

    private PacketMutexQueue PacketIn = new PacketMutexQueue(100, 5000);
    private PacketMutexQueue PacketOut = new PacketMutexQueue(100, 5000);
    private bool wantLocal = false;
    private Connection localConnection = new Connection();
    private Connection connection = new Connection();
    private Thread packetfactorythread;
    private Dispatcher dispatcher;
    private MutexBindingList<PD_Log> logs = new MutexBindingList<PD_Log>();
    protected Packet configuration;
    private ConfigurationCache configurationCache;
    private Thread sendLogsThread;
    private bool fetchingLogs;

    #endregion

    ~Device()
    {
        if ( Connection != null)
            if (Connection.Connected)
                Connection.Disconnect();
    }

    #region Properties

    [Browsable (false)]
    public virtual long PK { get; set; }

    [DescriptionAttribute("Connection Configuration"), DisplayName("Want Local Connection")]
    public virtual bool WantLocal
    {
        get { return wantLocal; }
        set { wantLocal = value; }
    }

    [DescriptionAttribute("Connection Configuration"), DisplayName("Local Connection")]
    public virtual Connection LocalConnection
    {
        get { return localConnection; }
        set { localConnection = value; }
    }

    [DescriptionAttribute("Connection Configuration"), DisplayName("Network Connection")]
    public virtual Connection Connection
    {
        get { return connection; }
        set { connection = value; }
    }

    [Browsable (false)]
    public virtual PacketMutexQueue PackQueueIn
    {
        get { return PacketIn; }
        set { PacketIn = value; }
    }

    [Browsable (false)]
    public virtual PacketMutexQueue PackQueueOut
    {
        get { return PacketOut; }
        set { PacketOut = value; }
    }

    [Browsable (false)]
    public virtual Thread PacketFactoryThread
    {
        get { return packetfactorythread; }
        set { packetfactorythread = value; }
    }

    [Browsable (false)]
    public virtual MutexBindingList<PD_Log> Logs
    {
        get { return logs; }
        set { logs = value; }
    }

    [CategoryAttribute("Configuration"),
        DescriptionAttribute("PD Configuration")]
    public virtual Packet Configuration
    {
        get { return configuration; }
        set { configuration = value; }
    }

    [Browsable (false)]
    public virtual ConfigurationCache ConfigurationCache
    {
        get { return configurationCache; }
        set { configurationCache = value; }
    }

    [Browsable (false)]
    public virtual Dispatcher Dispatcher
    {
        get { return dispatcher; }
        set { dispatcher = value; }
    }

    [Browsable (false)]
    public virtual Thread SendLogsThread
    {
        get { return sendLogsThread; }
        set { sendLogsThread = value; }
    }

    [Browsable (false)]
    public virtual bool FetchingLogs
    {
        get { return fetchingLogs; }
        set { fetchingLogs = value; }
    }

    #endregion
    }

And here is my Connection Class:

[TypeConverter(typeof(ExpandableObjectConverter))]
[CategoryAttribute("Connection")]
public class Connection
{
    #region Fields

    protected byte[] Data = new byte[2048];
    protected int size = 2048;
    protected StringMutexQueue InBuffer = new StringMutexQueue(100, 5000);
    protected StringMutexQueue OutBuffer = new StringMutexQueue(100, 5000);
    private bool connected;

    #endregion

    #region Properties

    [Browsable (false)]
    public virtual StringMutexQueue BufferIn
    {
        get { return InBuffer; }
        set { InBuffer = value; }
    }

    [Browsable(false)]
    public virtual StringMutexQueue BufferOut
    {
        get { return OutBuffer; }
        set { OutBuffer = value; }
    }

    [DescriptionAttribute("Connected")]
    public virtual bool Connected
    {
        get { return connected; }
        set { connected = value; }
    }

    [Browsable(false)]
    public virtual long PK { get; set; }

    #endregion

    public virtual void Connect()
    {
        throw new System.NotImplementedException();
    }

    public virtual void Disconnect()
    {
        throw new System.NotImplementedException();
    }

    public Connection() { }
}

I have 2 classes that are derived from the Connection class, ConnectionTCP and ConnectionSerial.

Finally, here is my mapping for Device:

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<class xmlns="urn:nhibernate-mapping-2.2" name="EMTRAC.Devices.Device, EMTRAC_v3, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" table="`Device`">
<id name="PK" type="System.Int64, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
  <column name="PK" />
  <generator class="identity" />
</id>
<many-to-one class="EMTRAC.Connections.Connection, EMTRAC_v3, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" name="LocalConnection" lazy="false" fetch="join" cascade="all">
  <column name="LocalConnection_id" />
</many-to-one>
<many-to-one class="EMTRAC.Connections.Connection, EMTRAC_v3, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" name="Connection" lazy="false" fetch="join" cascade="all" unique="true">
  <column name="Connection_id" />
</many-to-one>
<many-to-one class="EMTRAC.Packets.Packet, EMTRAC_v3, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" name="Configuration" lazy="false" cascade="all">
  <column name="Configuration_id" />
</many-to-one>
<joined-subclass name="EMTRAC.Intersections.Intersection, EMTRAC_v3, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
  <key>
    <column name="Device_id" />
  </key>
  <bag name="Zones">
    <key>
      <column name="Intersection_id" />
    </key>
    <one-to-many class="EMTRAC.Zones.Zone, EMTRAC_v3, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
  </bag>
  <many-to-one class="EMTRAC.Intersections.Streets, EMTRAC_v3, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" name="Streets" lazy="false" cascade="all">
    <column name="Streets_id" />
  </many-to-one>
  <many-to-one class="EMTRAC.Positions.Position, EMTRAC_v3, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" name="Position" cascade="all">
    <column name="Position" />
  </many-to-one>
</joined-subclass>
<joined-subclass name="EMTRAC.Vehicles.Vehicle, EMTRAC_v3, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
  <key>
    <column name="Device_id" />
  </key>
  <property name="Active" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
    <column name="Active" />
  </property>
  <property name="Status" type="System.Int32, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
    <column name="Status" />
  </property>
  <property name="Velocity" type="System.Int32, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
    <column name="Velocity" />
  </property>
  <property name="Heading" type="System.Int32, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
    <column name="Heading" />
  </property>
  <many-to-one class="EMTRAC.Positions.Position, EMTRAC_v3, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" name="Position" lazy="false" cascade="all">
    <column name="Position_id" />
  </many-to-one>
  <many-to-one class="EMTRAC.VehicleClasses.VehicleClass, EMTRAC_v3, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" name="VehClass" lazy="false" cascade="all">
    <column name="VehClass_id" />
  </many-to-one>
</joined-subclass>

The Intersection class derives from the Device base class.

My problem is that I can save the Intersection to the database and everything appears to be mapped correctly. However, after saving the Intersection and trying to use NHibernate to load the object using:

IQuery q = session.CreateQuery("from Device");
IList results = q.List();

I am provided with the following exception:

"could not load an entity: [EMTRAC.Connections.Connection#1][SQL: SELECT connection0_.PK as PK30_0_, connection0_.Connected as Connected30_0_, connection0_1_.Baud as Baud31_0_, connection0_1_.Port as Port31_0_, connection0_2_.EndPoint as EndPoint32_0_, connection0_2_.Port as Port32_0_, case when connection0_1_.Connection_id is not null then 1 when connection0_2_.Connection_id is not null then 2 when connection0_.PK is not null then 0 end as clazz_0_ FROM [Connection] connection0_ left outer join ConnectionSerial connection0_1_ on connection0_.PK=connection0_1_.Connection_id left outer join ConnectionTCP connection0_2_ on connection0_.PK=connection0_2_.Connection_id WHERE connection0_.PK=?]"

With an inner exception of:

{"Object reference not set to an instance of an object."}

My Device table has a PK column followed by columns for the LocalConnectionId and ConnectionId, as well as a Configuration column. The ID's in the LocalConnectionId and ConnectionId columns are mapped to the Connection table properly, which in turn is mapped to the appropriate derived class, ConnectionTCP or ConnectionSerial, and everything seems like it should work just fine.

I don't receive any errors saving the object.

I turned on showsql in the configuration and copied the sql statement it was using to load the object into my SQL Management Studio and the select statement executed just fine:

        declare @p0 BIGINT
    SET @p0 = 1


    NHibernate: 
    SELECT 
        connection0_.PK as PK30_0_, 
        connection0_.Connected as Connected30_0_, 
        connection0_1_.Baud as Baud31_0_, 
        connection0_1_.Port as Port31_0_, 
        connection0_2_.EndPoint as EndPoint32_0_, 
        connection0_2_.Port as Port32_0_, 
    case 
        when connection0_1_.Connection_id is not null then 1 
        when connection0_2_.Connection_id is not null then 2 
        when connection0_.PK is not null then 0 
    end 
    as clazz_0_ 

    FROM 
        [Connection] connection0_ left outer join ConnectionSerial connection0_1_ 
        on 
        connection0_.PK=connection0_1_.Connection_id left outer join ConnectionTCP connection0_2_ 
        on 
        connection0_.PK=connection0_2_.Connection_id 
    WHERE connection0_.PK=@p0

The only thing even remotely odd is that my EndPoint and Port are NULL, but that's only because I hadn't set those values for the object yet.

Any ideas what I am doing wrong?

Thanks in advance.

[EDIT] As requested here is the ConnectionTCP and ConnectionSerial classes:

[TypeConverter(typeof(ExpandableObjectConverter))]
public class ConnectionTCP : Connection
{
    #region Fields

    private TcpClient client;
    protected NetworkStream stream;
    private string endpoint;
    private int port;
    private int maxMessageSize = 4096;

    Thread commThread;

    #endregion

    #region Constructors

    public ConnectionTCP() { }

    public ConnectionTCP(string ipAdd, int port)
    {
        //  Set the Device EndPoint
        EndPoint = ipAdd;
        //  Set the Device Port
        Port = port;
        Client = new TcpClient(EndPoint, Port);
        //  Set Connected status
        Connected = false;
    }

    #endregion开发者_StackOverflow中文版

    #region Properties

    [Browsable(false)]
    public virtual long PK { get; set; }

    [Browsable(false)]
    public virtual TcpClient Client
    {
        get { return client; }
        set { client = value; }
    }

    [Browsable(false)]
    public virtual NetworkStream Stream
    {
        get { return stream; }
        set { stream = value; }
    }

    [CategoryAttribute("Network Address"),
        DisplayName("End Point"),
        DescriptionAttribute("The network address of the Priority Detector.")]
    public virtual string EndPoint
    {
        get { return endpoint; }
        set { endpoint = value; }
    }

    [CategoryAttribute("Port"), 
        DescriptionAttribute("The port used to connect to the Priority Detector.")]
    public virtual int Port
    {
        get { return port; }
        set { port = value; }
    }

    #endregion
    }

[TypeConverter(typeof(ExpandableObjectConverter))]
public class ConnectionSerial : Connection
{
    private Thread commThread;
    private int dataBits = 8;
    private Parity parity = Parity.None;
    private List<string> ports = new List<string>();
    private SerialPort serialConn;
    private StopBits stopBits = StopBits.One;
    private int timeoutRead = 10000;
    private int timeoutWrite = 10000;

    private int baud;
    private string port;

    [Browsable (false)]
    public virtual long PK { get; set; }

    [DescriptionAttribute("Serial Connection"), DisplayName("Serial Connection")]
    public virtual SerialPort SerialConn
    {
        get { return serialConn; }
        set { serialConn = value; }
    }

    [Browsable (false)]
    public virtual int Baud
    {
        get { return SerialConn.BaudRate; }
        set { baud = SerialConn.BaudRate; }
    }

    [Browsable(false)]
    public virtual string Port
    {
        get { return SerialConn.PortName; }
        set { port = SerialConn.PortName; }
    }

    #region Constructors

    public ConnectionSerial() { }

    public ConnectionSerial(string port, int baud)
    {
        SerialConn = new SerialPort();
        SerialConn.PortName = port;
        SerialConn.BaudRate = baud;
        SerialConn.Parity = parity;
        SerialConn.DataBits = dataBits;
        SerialConn.StopBits = stopBits;

        SerialConn.ReadTimeout = timeoutRead;
        SerialConn.WriteTimeout = timeoutWrite;

        //  Set Connected status
        Connected = false;
    }

    #endregion
    }

And here is the mapping for the Connections:

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
  <class xmlns="urn:nhibernate-mapping-2.2" name="EMTRAC.Connections.Connection, EMTRAC_v3, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" table="`Connection`">
<id name="PK" type="System.Int64, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
  <column name="PK" />
  <generator class="identity" />
</id>
<property name="Connected" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
  <column name="Connected" />
</property>
<joined-subclass name="EMTRAC.Connections.ConnectionSerial, EMTRAC_v3, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
  <key>
    <column name="Connection_id" />
  </key>
  <property name="Baud" type="System.Int32, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
    <column name="Baud" />
  </property>
  <property name="Port" type="System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
    <column name="Port" />
  </property>
</joined-subclass>
<joined-subclass name="EMTRAC.Connections.ConnectionTCP, EMTRAC_v3, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
  <key>
    <column name="Connection_id" />
  </key>
  <property name="EndPoint" type="System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
    <column name="EndPoint" />
  </property>
  <property name="Port" type="System.Int32, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
    <column name="Port" />
  </property>
  <!--<property name="Client" type="EMTRAC.Connections.TcpClientMapper, EMTRAC_v3"/>-->
  <!--<property name="Client" type="EMTRAC.Connections.TcpClientMapper, EMTRAC_v3" />-->
</joined-subclass>


NHibernate is trying to load a ConnectionSerial object from the database. When it tries to set the values of the Baud and Port properties, a NullReferenceException is thrown because SerialConn does not have a value yet.

0

精彩评论

暂无评论...
验证码 换一张
取 消