Closed
Description
I've created a little test project which runs on .NET Framework 4.8 and using NHibernate 5.3.5 which throws:
System.ArgumentNullException: 'Value cannot be null.
at System.Collections.Generic.HashSet`1..ctor(IEnumerable`1 collection, IEqualityComparer`1 comparer)
at NHibernate.Proxy.NHibernateProxyFactoryInfo.CreateProxyFactory()
at NHibernate.Proxy.NHibernateProxyObjectReference.GetRealObject(StreamingContext context)
at System.Runtime.Serialization.ObjectManager.ResolveObjectReference(ObjectHolder holder)
at System.Runtime.Serialization.ObjectManager.DoFixups()
at System.Runtime.Serialization.Formatters.Binary.ObjectReader.Deserialize(HeaderHandler handler, __BinaryParser serParser, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream, HeaderHandler handler, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage)
at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream)
The database design is as follows:
create table [Role]
(
RoleID int,
[Name] nvarchar(50),
PRIMARY KEY (RoleID)
)
create table [Resource]
(
ResourceID int,
[Name] nvarchar(50),
RoleID int,
ManagerID int,
PRIMARY KEY (ResourceID),
FOREIGN KEY (RoleID) REFERENCES [Role](RoleID),
FOREIGN KEY (ManagerID) REFERENCES [Resource](ResourceID)
)
insert [Role] (RoleID, [Name])
values (1, 'role1')
insert [Role] (RoleID, [Name])
values (2, 'role2')
insert [Resource] (ResourceID, [Name], RoleID, ManagerID)
values (1, 'res1', 1, null)
insert [Resource] (ResourceID, [Name], RoleID, ManagerID)
values (2, 'res2', 2, 1)
There are two classes:
using System;
namespace NHibernate.Bug
{
[Serializable]
public class Role
{
public virtual string Name { get; set; }
public virtual int Key { get; set; }
}
}
using System;
namespace NHibernate.Bug
{
[Serializable]
public class Resource
{
public virtual int Key { get; set; }
public virtual Resource Manager { get; set; }
public virtual string Name { get; set; }
public virtual Role ResourceRole { get; set; }
}
}
and their mappings are:
<?xml version="1.0"?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="NHibernate.Bug"
namespace="NHibernate.Bug">
<class name="Role" table="Role">
<id name="Key">
<column name="RoleID" sql-type="int" not-null="true"/>
<generator class="assigned" />
</id>
<property name="Name"/>
</class>
</hibernate-mapping>
<?xml version="1.0"?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="NHibernate.Bug"
namespace="NHibernate.Bug">
<class name="Resource" table="Resource" dynamic-insert="true">
<id name="Key" column="ResourceID" >
<generator class="assigned" />
</id>
<property name="Name"/>
<many-to-one name="Manager" class="Resource" column="ManagerID"/>
<many-to-one name="ResourceRole" class="Role" column="RoleID"/>
</class>
</hibernate-mapping>
The code that is failing is:
var session = CreateSessionFactory().OpenSession();
// if we don't run this line the test passes
var resource1 = session.CreateCriteria<Resource>("r").Add(Restrictions.Eq("r.Key", 2)).UniqueResult<Resource>();
var resource2 = session.QueryOver<Resource>()
.Where(res => res.Key == 2)
.Fetch(SelectMode.Fetch, res => res.Manager)
.SingleOrDefault();
var serialised = Serialize(resource2);
var deserialised = Deserialize(serialised);
For some reason it only fails if we execute the criteria query before the queryover one.
Please see below the full fixture code:
using Microsoft.VisualStudio.TestTools.UnitTesting;
using NHibernate.Cfg;
using NHibernate.Criterion;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
namespace NHibernate.Bug
{
[TestClass]
public class ProxyFixture
{
[TestMethod]
public void ItShouldSerializeAndDeserialize()
{
var session = CreateSessionFactory().OpenSession();
// if we don't run this line the test passes
var resource1 = session.CreateCriteria<Resource>("r").Add(Restrictions.Eq("r.Key", 2)).UniqueResult<Resource>();
var resource2 = session.QueryOver<Resource>()
.Where(res => res.Key == 2)
.Fetch(SelectMode.Fetch, res => res.Manager)
.SingleOrDefault();
var serialised = Serialize(resource2);
var deserialised = Deserialize(serialised);
}
private ISessionFactory CreateSessionFactory()
{
var config = new Configuration();
config.SetProperty(Environment.ConnectionString, "Server=xxx;Database=xxx;User Id=xxx;Password=xxx;");
config.SetProperty(Environment.ConnectionDriver, "NHibernate.Driver.SqlClientDriver");
config.SetProperty(Environment.Dialect, "NHibernate.Dialect.MsSql2012Dialect, NHibernate");
config.SetProperty(Environment.ShowSql, "false");
config.SetProperty(Environment.DefaultFlushMode, "Commit");
config.SetProperty(Environment.FormatSql, "false");
config.SetProperty(Environment.BatchSize, "50");
config.AddAssembly(GetType().Assembly);
return config.BuildSessionFactory();
}
protected byte[] Serialize(object value)
{
var formatter = new BinaryFormatter();
using (var stream = new MemoryStream())
{
formatter.Serialize(stream, value);
var result = new byte[stream.Length];
stream.Position = 0;
stream.Read(result, 0, (int)stream.Length);
stream.Close();
return result;
}
}
protected object Deserialize(byte[] state)
{
using (MemoryStream stream = new MemoryStream())
{
stream.Write(state, 0, state.Length);
stream.Position = 0;
var formatter = new BinaryFormatter();
return formatter.Deserialize(stream);
}
}
}
}