Problem loading an object with 2 properties of the same class with NHibernate after saving from previous session
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.
精彩评论