Exception in RelationCollection after it's been deserialized in 5.1.1

Posts   
 
    
Posts: 98
Joined: 10-Nov-2006
# Posted on: 03-Jan-2017 22:00:33   

Library version 5.1.1 .NET 4.6 SelfServicing

I have code that creates a RelationCollection, then serializes it, and then (sometime later) deserializes it and uses it in a call to collection.GetMulti. This worked fine with v5.0, but after upgrading to 5.1.1 it's crashing.

Code is something like this:


...
var relations = GetRelations();  // Creates a relation collection and sets it up
var formatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
var stream = new System.IO.MemoryStream();
formatter.Serialize(stream, relations);
stream.Seek(0, System.IO.SeekOrigin.Begin);
var relationsCopy = (IRelationCollection)formatter.Deserialize(stream);
collection.GetMulti(predicate, maximumRows, llblSort, relations, prefetchPath, includeFields,
                maximumRows == 0 ? 0 : (startRowIndex / maximumRows + 1), maximumRows);

The exception is:


System.Web.HttpUnhandledException (0x80004005): Object reference not set to an instance of an object. ---> System.NullReferenceException: Object reference not set to an instance of an object.
   at SD.LLBLGen.Pro.ORMSupportClasses.RelationCollection.ToQueryTextInternal(Boolean ansiJoins, String& nonAnsiWhereClause, String nonAnsiRootTableReference, String nonAnsiFieldSuffix)
   at SD.LLBLGen.Pro.ORMSupportClasses.RelationCollection.ToQueryText()
   at SD.LLBLGen.Pro.DQE.SqlServer.DynamicQueryEngine.CreateSelectDQ(IEntityFieldCore[] selectList, IFieldPersistenceInfo[] fieldsPersistenceInfo, IRetrievalQuery query, IPredicate selectFilter, Int64 maxNumberOfItemsToReturn, ISortExpression sortClauses, IRelationCollection relationsToWalk, Boolean allowDuplicates, IGroupByCollection groupByClause, Boolean relationsSpecified, Boolean sortClausesSpecified)
   at SD.LLBLGen.Pro.ORMSupportClasses.DynamicQueryEngineBase.CreateSelectDQ(IEntityFieldCore[] selectList, IFieldPersistenceInfo[] fieldsPersistenceInfo, DbConnection connectionToUse, IPredicate selectFilter, Int64 maxNumberOfItemsToReturn, ISortExpression sortClauses, IRelationCollection relationsToWalk, Boolean allowDuplicates, IGroupByCollection groupByClause)
   at SD.LLBLGen.Pro.DQE.SqlServer.DynamicQueryEngine.CreatePagingSelectDQ(IEntityFieldCore[] selectList, IFieldPersistenceInfo[] fieldsPersistenceInfo, DbConnection connectionToUse, IPredicate selectFilter, Int32 rowsToSkip, Int32 rowsToTake, ISortExpression sortClauses, IRelationCollection relationsToWalk, Boolean allowDuplicates, IGroupByCollection groupByClause)
   at SD.LLBLGen.Pro.ORMSupportClasses.DynamicQueryEngineBase.CreateSelectDQ(IEntityFieldCore[] selectList, IFieldPersistenceInfo[] fieldsPersistenceInfo, DbConnection connectionToUse, IPredicate selectFilter, Int32 rowsToSkip, Int32 rowsToTake, ISortExpression sortClauses, IRelationCollection relationsToWalk, Boolean allowDuplicates, IGroupByCollection groupByClause)
   at SD.LLBLGen.Pro.ORMSupportClasses.DaoBase.CreateSelectQueryForGetMulti(QueryParameters parameters, DbConnection connectionToUse)
   at SD.LLBLGen.Pro.ORMSupportClasses.DaoBase.PerformGetMultiAction(ITransaction containingTransaction, QueryParameters parameters)
   at SD.LLBLGen.Pro.ORMSupportClasses.DaoBase.GetMulti(ITransaction containingTransaction, IEntityFactory entityFactoryToUse, QueryParameters parameters)
   at SD.LLBLGen.Pro.ORMSupportClasses.EntityCollectionBase`1.PerformGetMulti(QueryParameters parameters)
   at SD.LLBLGen.Pro.ORMSupportClasses.EntityCollectionBase`1.GetMulti(IPredicate selectFilter, Int64 maxNumberOfItemsToReturn, ISortExpression sortClauses, IRelationCollection relations, IPrefetchPath prefetchPathToUse, ExcludeIncludeFieldsList excludedIncludedFields, Int32 pageNumber, Int32 pageSize)

I compiled a debug version of 5.1.1, and the problem is near line 400:

foreach(var fcd in _fromClauseDirectives)
{
    fcdsPerAlias.Add(fcd.Alias, fcd);
}

_fromClauseDirectives is null, because it's marked as NonSerialized, and not initialized when creating the RelationCollection via deserialization.

daelmo avatar
daelmo
Support Team
Posts: 8245
Joined: 28-Nov-2005
# Posted on: 04-Jan-2017 07:43:09   

Please post the code for GetRelations. If you back to v5.0 Does it work?

David Elizondo | LLBLGen Support Team
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39588
Joined: 17-Aug-2003
# Posted on: 04-Jan-2017 10:55:15   

serialization is done using a normal binary formatter? Or xml serialization?

Frans Bouma | Lead developer LLBLGen Pro
Posts: 98
Joined: 10-Nov-2006
# Posted on: 04-Jan-2017 17:40:36   

The GetRelations() call was just an example - I've seen this fail in my code with multiple different RelationCollections, and I assume that even replacing GetRelations() with "new RelationCollection()" would show the issue.

I'm using regular .net binary serialization. See my initial post for example code of how I serialize. (Look for "new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter")

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39588
Joined: 17-Aug-2003
# Posted on: 04-Jan-2017 18:37:21   

Ok, I should have read the code better indeed flushed

Binary serialization of lowlevel api elements isn't really supported, but at the same time it's required for e.g. datasourcecontrols as these serialize their contents binary into the viewstate so an implementation has to work.

We'll look into what the change was in that area which triggered this issue. It should be easy enough to reproduce.

Frans Bouma | Lead developer LLBLGen Pro
Posts: 98
Joined: 10-Nov-2006
# Posted on: 04-Jan-2017 20:30:59   

Here's some real code that reproduces the problem. I picked an "ItemEntity" in my example, but I believe any entity and any relation would show the same issue:


var relations = new RelationCollection();
relations.Add(Data.Data.EntityClasses.ItemEntity.Relations.PackageEntityUsingPackageId);

var formatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
var stream = new System.IO.MemoryStream();
formatter.Serialize(stream, relations);
stream.Seek(0, System.IO.SeekOrigin.Begin);

var relationsCopy = (IRelationCollection) formatter.Deserialize(stream);

var coll = new Data.Data.CollectionClasses.ItemCollection();

coll.GetMulti(null, 0, null, relations); // Works
coll.GetMulti(null, 0, null, relationsCopy); // Fails

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39588
Joined: 17-Aug-2003
# Posted on: 05-Jan-2017 12:24:13   

Fixed in new 5.1.2 hotfix build which is now available.

Classical error: the default CTor isn't run when deserializing objects using the binary formatter if there's no ISerializable interface implementation.

Frans Bouma | Lead developer LLBLGen Pro
Posts: 98
Joined: 10-Nov-2006
# Posted on: 05-Jan-2017 22:07:33   

Thanks for the quick fix.

Also, I'm happy to see that you publish the hotfixes as pre-release nuget packages - I was worried that it was going to be a pain to switch over to the hotfix, but the nuget package made it easy.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39588
Joined: 17-Aug-2003
# Posted on: 05-Jan-2017 22:19:10   

wesleysmith wrote:

Thanks for the quick fix.

Also, I'm happy to see that you publish the hotfixes as pre-release nuget packages - I was worried that it was going to be a pain to switch over to the hotfix, but the nuget package made it easy.

simple_smile

Frans Bouma | Lead developer LLBLGen Pro
Posts: 36
Joined: 02-May-2012
# Posted on: 10-Jan-2017 03:19:12   

I am getting this error using adapter after upgrading to 5.1. I just put together a sample app for you for to reproduce it. Glad someone else also had it happen...will try the hotfix now.

Thanks

Kerry

Posts: 36
Joined: 02-May-2012
# Posted on: 10-Jan-2017 18:24:36   

Updated to 5.1.2.

Visualizer and code seem to be working correctly now.

Thanks