Dynamic Linq: "Nullable object must have a value." on .NET 6.0

367 Views Asked by At

I have the following dynamic LINQ running without error on .NET Core 3.1.

query = query.GroupJoin(ParsingConfig.DefaultEFCore21,
                                detailObject,
                                "new { it.ExternalDataId2.Value AS I0}",
                                "new { Id AS I0}",
                                "new (outer AS A, inner AS B)");

query = query.SelectMany("B.DefaultIfEmpty()",
                         "new { source.A.Id AS Id,source.A.ExternalDataId2 AS ExternalDataId2,detail.Title AS ExternalData2Ref_Title,detail.Id AS ExternalData2Ref_Id}",
                         "source",
                         "detail");

query.ToDynamicListAsync();

I am porting my application to .NET 6.0 and have this error: Nullable object must have a value.

I tried removing "ParsingConfig" without solving the problem. Using SQL Profiler I saw that the query is executed.

Full exception stacktrace:

Message: 
Test method FrameworkTests.DataLayer.FindTests.FindValueExternal threw exception: 
NTSFramework.DataLayer.DataLayerException: Errore generico di repository Nullable object must have a value.
 ---> System.InvalidOperationException: Nullable object must have a value.

  Stack Trace: 
lambda_method559(Closure , QueryContext , DbDataReader , ResultContext , SingleQueryResultCoordinator )
AsyncEnumerator.MoveNextAsync()
DynamicEnumerableAsyncExtensions.ToListAsync[T](IEnumerable source, CancellationToken cancellationToken)
DynamicEnumerableAsyncExtensions.ToListAsync[T](IEnumerable source, CancellationToken cancellationToken)
BaseDataLayer.FindValuesAsync[TModel](FindValuesOptions findOptions) line 866

Changing the SelectMany as below no longer generates the error, but it's not the result I need:

query = query.SelectMany("B.DefaultIfEmpty()",
                     "new { source.A.Id AS Id,source.A.ExternalDataId2 AS ExternalDataId2,detail As ExternalData2Ref}",
                     "source",
                     "detail");
1

There are 1 best solutions below

0
G Wimpassinger On BEST ANSWER

The problem arises from your B.DefaultIfEmpty() in your SelectMany expression. If the join does not yield any Bs your detail entity is null and you cannot dereference detail.Title or detail.Id.

You can either explicitly check for null and instead of just detail.Title you have to writedetail != null ? detail.Title : string.Empty AS ExternalData2Ref_Title. Or you may use the Dynamic LINQ null propagating function np() and write np(detail.Title).

In your code it should look like this (I assumed detail.Id is of type int):

query = query.SelectMany("B.DefaultIfEmpty()",
                     "new { source.A.Id AS Id,source.A.ExternalDataId2 AS ExternalDataId2, np(detail.Title) AS ExternalData2Ref_Title, detail != null ? detail.Id : 0 AS ExternalData2Ref_Id}",
                     "source",
                     "detail");