So I have a class:
public class objWalkdown {
private objWalkdown_ID _walkdownId = new objWalkdown_ID();
public virtual objWalkdown_ID Id {
get { return _walkdownId; }
set { _walkdownId = value; }
}
public virtual String facility {
get { return _walkdownId.facility; }
set { _walkdownId.facility = value; }
}
public virtual String walkdown {
get { return _walkdownId.walkdown; }
set { _walkdownId.walkdown = value; }
}
public virtual String activity {
get { return _walkdownId.activity; }
set { _walkdownId.activity = value; }
}
public virtual Boolean complete { get; set; }
public virtual Byte[] filedata { get; set; }
}
That utilizes a composite id setup in another class:
[Serializable]
public class objWalkdown_ID {
public virtual String facility { get; set; }
public virtual String walkdown { get; set; }
public virtual String activity { get; set; }
}
From my research this serialized composite key is required in order to facilitate lazy loading on a property (i.e. a regular composite key setup will not work),shown here is my Fluent NNibernate mapping class:
public class objWalkdown_ORM : ClassMap<objWalkdown> {
public objWalkdown_ORM() {
Id(x => x.Id);
Map(x => x.facility);
Map(x => x.walkdown);
Map(x => x.activity);
Map(x => x.complete);
Map(x => x.filedata)
.CustomType("BinaryBlob")
.LazyLoad();
Table("tbPDFs");
}
}
And this 100% works when NHibernate was hooked up to my SQLite test database, but when moved to SQL Server 2008 things broke a bit. The only real DB changes being the SQLite BINARY
type to the SQL Server 2008 VARBINARY(MAX)
type. However with lazy loading disabled everything works on both sides, it's only when my property is tagged with the lazy loading option that things start to break. Here is a sample of how I'm accessing the data:
public Stream getWalkdown(String Facility, String Walkdown, String Activity) {
//Use NHibernate Session setup "Per-Request"
ISession session = (ISession)HttpContext.Current.Items["NHSession"];
//Build composite Id
objWalkdown_ID id = new objWalkdown_ID() { facility = Facility, walkdown = Walkdown, activity = Activity };
//Get the entity
objWalkdown walkdown = session.Get<objWalkdown>(id);
//Lazy Load File Data and return a memory stream
return new MemoryStream(walkdown.filedata);
}
Please focus on the lazy loading portion and don't ask me to not use it, the purpose of this question is to determine exactly what is wrong with the lazy loading. Like I stated, using SQLite this functions 100%. It will also work under both SQLite and SQL Server 2008 if the lazy loading is removed, so I don't think it's the actual data types on the back end.
The specific error I encounter, when inspecting the walkdown object (prior to the lazy load) is "System.InvalidOperationException - Invalid attempt to read when no data is present". However there definitely is data present. So I'm thinking this is an issue with the NHibernate proxy.
Here is a stack trace:
at System.Data.SqlClient.SqlDataReader.ReadColumnHeader(Int32 i)
at System.Data.SqlClient.SqlDataReader.IsDBNull(Int32 i)
at NHibernate.Driver.NHybridDataReader.IsDBNull(Int32 i)
at NHibernate.Type.NullableType.NullSafeGet(IDataReader rs, String name)
at NHibernate.Type.NullableType.NullSafeGet(IDataReader rs, String[] names, ISessionImplementor session, Object owner)
at NHibernate.Persister.Entity.AbstractEntityPersister.InitializeLazyPropertiesFromDatastore(String fieldName, Object entity, ISessionImplementor session, Object id, EntityEntry entry)
at NHibernate.Persister.Entity.AbstractEntityPersister.InitializeLazyProperty(String fieldName, Object entity, ISessionImplementor session)
at NHibernate.Intercept.AbstractFieldInterceptor.InitializeField(String fieldName, Object target)
at NHibernate.Intercept.AbstractFieldInterceptor.Intercept(Object target, String fieldName, Object value)
at NHibernate.Intercept.DefaultDynamicLazyFieldInterceptor.Intercept(InvocationInfo info)
at objWalkdownProxy.get_filedata()
I hope someone can give me some advice on a proper solution. I already have a work around, but it involves HQL and eagerly loading an entity when I require the file data, which is not what I want to be doing.