- Home
- LLBLGen Pro
- Bugs & Issues
DataAccessAdapter.FetchEntityCollection returns ArgumentNullException on Oracle CLOB data type
Joined: 11-Mar-2021
I ran a simple FetchEntityCollection on a table to get all entities, using the DataAccessAdapter. No RelationPredicateBucket and no PrefetchPath (i.e. both are null). This triggered the following System.ArgumentNullException : 'Value cannot be null. Parameter name: value'
Stack Trace:
at System.BitConverter.ToString(Byte[] value, Int32 startIndex, Int32 length) at OracleInternal.TTC.TTCLob.GetLobIdString(Byte[] lobLocator) at OracleInternal.ServiceObjects.OracleDataReaderImpl.CollectTempLOBsToBeFreed(Int32 rowNumber) at Oracle.ManagedDataAccess.Client.OracleDataReader.ProcessAnyTempLOBs(Int32 rowNumber) at Oracle.ManagedDataAccess.Client.OracleDataReader.Read() at SD.LLBLGen.Pro.ORMSupportClasses.EntityMaterializerBase.Materialize(Func`4 valueReadErrorHandler, String& failureErrorText) at SD.LLBLGen.Pro.ORMSupportClasses.DataAccessAdapterCore.ExecuteMultiRowRetrievalQuery(IRetrievalQuery queryToExecute, IEntityFactory2 entityFactory, IEntityCollection2 collectionToFill, IFieldPersistenceInfo[] fieldsPersistenceInfo, Boolean allowDuplicates, IEntityFields2 fieldsUsedForQuery) at SD.LLBLGen.Pro.ORMSupportClasses.DataAccessAdapterCore.FetchEntityCollectionInternal(QueryParameters parameters) at SD.LLBLGen.Pro.ORMSupportClasses.DataAccessAdapterCore.FetchEntityCollection(QueryParameters parameters) at SD.LLBLGen.Pro.ORMSupportClasses.DataAccessAdapterBase.<>c__DisplayClass10_0.<FetchEntityCollection>b__0() at SD.LLBLGen.Pro.ORMSupportClasses.DataAccessAdapterBase.ExecuteWithActiveRecoveryStrategy(Action toExecute) at SD.LLBLGen.Pro.ORMSupportClasses.DataAccessAdapterBase.FetchEntityCollection(QueryParameters parameters) at SD.LLBLGen.Pro.ORMSupportClasses.DataAccessAdapterCore.FetchEntityCollection(IEntityCollection2 collectionToFill, IRelationPredicateBucket filterBucket, Int32 maxNumberOfItemsToReturn, ISortExpression sortClauses, IPrefetchPath2 prefetchPath, ExcludeIncludeFieldsList excludedIncludedFields, Int32 pageNumber, Int32 pageSize) at SD.LLBLGen.Pro.ORMSupportClasses.DataAccessAdapterCore.FetchEntityCollection(IEntityCollection2 collectionToFill, IRelationPredicateBucket filterBucket, IPrefetchPath2 prefetchPath)
- Bookkeeping:
- LLBLGen Pro Editor v5.8.0
- SD.LLBLGen.Pro.DQE.OracleODPNET v5.8.0
- SD.LLBLGen.Pro.ORMSupportClasses v5.8.0
- Oracle Database 12cR2 64-bit
- Oracle.ManagedDataAccess v12.2.1100
- .NET Framework 4.7.2
The Oracle table entities we are retrieving have two CLOB fields. Because the error occurred while trying to convert a Byte Array to a String, I believe the CLOB fields are responsible for the ArgumentNullException. We call this method from a Service we created:
public IEnumerable<T> FetchEntityCollection(RelationPredicateBucket predicateBucket = null, PrefetchPath2 preFetchPath = null) {
using (var adapter = new DataAccessAdapter(_connectionString)) {
var data = new EntityCollection<T>();
adapter.FetchEntityCollection(data, predicateBucket, preFetchPath);
return data;
}
}
The table has no foreign keys. It has a compound primary key (two fields, one Varchar2 and one Date). The entity definition was created directly from the database table, using the LLBLGen Pro reverse-engineering feature. It seems like I'm running a fairly straightforward use case, so I'm surprised that it is crashing.
I did try changing the entity data type for the CLOBS from String to Byte[], but it still threw an exception.
Any help you could provide would be appreciated.
Joined: 17-Aug-2003
As the crash happens in the Oracle ADO.NET provider, there's little we can do: it happens during the read action of the datareader, as you can see from the stacktrace. From the looks of it, they pass a null value to the bitconverter while they should have tested for that. Oracle has released newer ODP.NET versions than the one you're using tho, could you try a newer one from nuget to see if the problem has been fixed in their provider?
I see in the 19.0.0 version they do a null check at least: (decompiled). I added a comment below in the code
internal void CollectTempLOBsToBeFreed(int rowNumber, ArrayList tempLOBArrayList)
{
if (ProviderConfig.m_bTraceLevelPrivate)
{
Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)262400, OracleTraceClassName.OracleDataReaderImpl, OracleTraceFuncName.CollectTempLOBsToBeFreed);
}
if (m_accessors != null)
{
for (int i = 0; i < m_accessors.Length; i++)
{
if (!(m_accessors[i] is TTCLobAccessor))
{
continue;
}
TTCLobAccessor tTCLobAccessor = m_accessors[i] as TTCLobAccessor;
if (tTCLobAccessor.AbstractOrTempLOB(rowNumber))
{
byte[] lobLocator = tTCLobAccessor.GetLobLocator(rowNumber);
if (lobLocator == null) // <<<<<<<<<<<< This one is likely not present in 12.2
{
continue;
}
if (m_connectionImpl.TemporaryLobReferenceGet(TTCLob.GetLobIdString(lobLocator)) == null)
{
if (tTCLobAccessor.m_definedColumnType == OraType.ORA_OCICLobLocator)
{
tempLOBArrayList.Add(new OracleClobImpl(m_connectionImpl, lobLocator, bNClob: false));
}
else if (tTCLobAccessor.m_definedColumnType == OraType.ORA_OCIBLobLocator)
{
tempLOBArrayList.Add(new OracleBlobImpl(m_connectionImpl, lobLocator, bCaching: false));
}
}
tTCLobAccessor.m_lobLocators[rowNumber].Clear();
}
else if (tTCLobAccessor.m_lobLocators[rowNumber] != null && tTCLobAccessor.m_lobLocators[rowNumber].Count > 0)
{
tTCLobAccessor.m_lobLocators[rowNumber].Clear();
}
}
}
if (ProviderConfig.m_bTraceLevelPrivate)
{
Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)262656, OracleTraceClassName.OracleDataReaderImpl, OracleTraceFuncName.CollectTempLOBsToBeFreed);
}
}