Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

System.NullReferenceException thrown #21398

Closed
henrikdahl8240 opened this issue Jun 24, 2020 · 23 comments
Closed

System.NullReferenceException thrown #21398

henrikdahl8240 opened this issue Jun 24, 2020 · 23 comments
Labels
closed-no-further-action The issue is closed and no further action is planned. customer-reported

Comments

@henrikdahl8240
Copy link

I have an OData query like:
...Bikes(1)/ns.MountainBike?$expand=Children($select=P1,P2,ns.A/P3,ns.B/P4)

Some of the instances in Children are of type A, none are of type B.

Unfortunately this exception is being thrown:

System.NullReferenceException: Object reference not set to an instance of an object.
   at lambda_method36509(Closure , QueryContext , DbDataReader , ResultContext , ResultCoordinator )
   at Microsoft.EntityFrameworkCore.Query.RelationalShapedQueryCompilingExpressionVisitor.CustomShaperCompilingExpressionVisitor.
<PopulateCollection>g__ProcessCurrentElementRow|7_1[TCollection,TElement,TRelatedEntity](<>c__DisplayClass7_0`3& )
   at Microsoft.EntityFrameworkCore.Query.RelationalShapedQueryCompilingExpressionVisitor.CustomShaperCompilingExpressionVisitor.PopulateCollection[TCollection,TElement,TRelatedEntity](Int32 collectionId, QueryContext queryContext, DbDataReader dbDataReader, ResultCoordinator resultCoordinator, Func`3 parentIdentifier, Func`3 outerIdentifier, Func`3 selfIdentifier, IReadOnlyList`1 parentIdentifierValueComparers, IReadOnlyList`1 outerIdentifierValueComparers, IReadOnlyList`1 selfIdentifierValueComparers, Func`5 innerShaper)
   at lambda_method36510(Closure , QueryContext , DbDataReader , ResultContext , Int32[] , ResultCoordinator )
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryingEnumerable`1.Enumerator.MoveNext()
   at Microsoft.AspNet.OData.EnableQueryAttribute.SingleOrDefault(IQueryable queryable, IWebApiActionDescriptor actionDescriptor)
   at Microsoft.AspNet.OData.EnableQueryAttribute.ExecuteQuery(Object responseValue, IQueryable singleResultCollection, IWebApiActionDescriptor actionDescriptor, Func`2 modelFunction, IWebApiRequestMessage request, Func`2 createQueryOptionFunction)
   at Microsoft.AspNet.OData.EnableQueryAttribute.OnActionExecuted(Object responseValue, IQueryable singleResultCollection, IWebApiActionDescriptor actionDescriptor, IWebApiRequestMessage request, Func`2 modelFunction, Func`2 createQueryOptionFunction, Action`1 createResponseAction, Action`3 createErrorAction)
   at Microsoft.AspNet.OData.EnableQueryAttribute.OnActionExecuted(ActionExecutedContext actionExecutedContext)
   at Microsoft.AspNetCore.Mvc.Filters.ActionFilterAttribute.OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.
    <InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync()
--- End of stack trace from previous location ---
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.
        <InvokeFilterPipelineAsync>g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.
            <InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
   at Microsoft.AspNetCore.Routing.EndpointMiddleware.
                <Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
   at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

If I do this query instead, it works fine:
...Bikes(1)/ns.MountainBike?$expand=Children($select=P1,P2,ns.A/P3)

If I do this query, I get the same exception:
...Bikes(1)/ns.MountainBike?$expand=Children($select=ns.B/P4)

Therefore it looks to me like if I use a cast for a type of which no instances match, I get the exception.

Is this enough information, because it takes a lot of time for me to make a concrete sample which demonstrates it?

I use Microsoft.AspNetCore.OData 7.4.1 and .Net 5.0 preview 5.

@ErikEJ
Copy link
Contributor

ErikEJ commented Jun 24, 2020

Wonder if OData has been tested with EF Core 5?

@henrikdahl8240
Copy link
Author

Yes, there could be such a maturity problem or the other way around, that EF Core 5 is not being tested with OData.

I have made one more observations: If I query the whole collection of bikes, i.e. do not specify the key, I get the same exception, i.e.:
...Bikes/ns.MountainBike?$expand=Children($select=P1,P2,ns.A/P3,ns.B/P4)

BUT if the Bikes collection is empty, i.e. the Bikes table in the database has no rows, the query executes correctly without any exception!!

To me it looks immature, i.e. simple cases you should expect to occur over and over again have not been taken into account.

@smitpatel
Copy link
Member

Please share a runnable repro code. Possibly without using OData.

@henrikdahl8240
Copy link
Author

Now I obviously don't know if you know OData, but do you know if I can somehow get the query which OData produces so I can be sure I query EF Core the same way but eliminates OData, because I just issue the query which OData would have been producing?

Can EF Core for instance log the query it receives because I can also take it from the recipient side of course?

@smitpatel
Copy link
Member

I will wait for someone to respond to OData/WebApi#2206 and isolate EF Core issue if any.

@ajcvickers
Copy link
Member

@ErikEJ We have been planning OData testing for 5.0. I created #21402 to track it.

@henrikdahl8240
Copy link
Author

@smitpatel As far as I know, I have now published a tiny sample to Github: https://github.com/henrikdahl8240/CastProblem20200624

You may see the few simple steps in todo.txt, which you can just copy/paste to your machine.

Can you see the problem now?

@henrikdahl8240
Copy link
Author

Unfortunately .NET 5.0 Preview 6 results in the same exception.

I hope you may take a look into it. There are only a few lines of code in the sample and it will take you very short time to familiarize yourself with it.

@ajcvickers
Copy link
Member

I can reproduce this, but I don't know how to get the IQueryable that OData is generating. Does anyone know where to set a breakpoint or something else that can be done to figure out what query OData is generating?

@xuzhg
Copy link

xuzhg commented Jun 30, 2020

@ajcvickers

Can the following log help you?

info: Microsoft.EntityFrameworkCore.Infrastructure[10403]
      Entity Framework Core 5.0.0-preview.5.20278.2 initialized 'CastProblemDbContext' using provider 'Microsoft.EntityFrameworkCore.SqlServer' with options: using lazy-loading proxies CommandTimeout=600
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
      Executed DbCommand (75ms) [Parameters=[@__TypedProperty_1='?' (Size = 4000)], CommandType='Text', CommandTimeout='600']
      SELECT [b].[ID], [b].[Discriminator], [b].[Version], [b].[CategoryParentID], [t].[c], [t].[c0], [t].[ID], [t].[c1], [t].[Version], CASE
          WHEN [b1].[Discriminator] = CAST(8 AS tinyint) THEN N'CastProblem20200624.BikeShop_Good__Local__BikeShop_BibliographicalRecordInventory'
          WHEN [b1].[Discriminator] = CAST(7 AS tinyint) THEN N'CastProblem20200624.BikeShop_Good__Local__BikeShop'
          WHEN [b1].[Discriminator] = CAST(0 AS tinyint) THEN N'CastProblem20200624.BikeShop_Good_Z3950Target'
          ELSE N'CastProblem20200624.BikeShop_Good'
      END, [b1].[ID], [b1].[Version], CASE
          WHEN [b1].[Discriminator] = CAST(0 AS tinyint) THEN N'ISIL_Number'
          ELSE NULL
      END, [b1].[ISIL_Number], NULL, [b1].[BikeShopID], [b1].[CategoryID], [b1].[Discriminator], [b1].[Preferred_PropertyUri_For_BibliographicalRecord], [b1].[Target_BikeShopID], [b1].[Target_BikeShop_BibliographicalRecordInventoryID]
      FROM [BikeShop_GoodCategorys] AS [b]
      LEFT JOIN (
          SELECT @__TypedProperty_1 AS [c], N'ID' AS [c0], [b0].[ID], N'Version' AS [c1], [b0].[Version], [b0].[CategoryParentID]
          FROM [BikeShop_GoodCategorys] AS [b0]
          WHERE [b0].[Discriminator] = CAST(1 AS tinyint)
      ) AS [t] ON [b].[ID] = [t].[CategoryParentID]
      LEFT JOIN [BikeShop_Goods] AS [b1] ON [b].[ID] = [b1].[CategoryID]
      WHERE [b].[Discriminator] = CAST(1 AS tinyint)
      ORDER BY [b].[ID], [t].[ID], [b1].[ID]

@smitpatel
Copy link
Member

We need actual LINQ query. The error message indicates that the shaper created for materializing collection has null ref error. We cannot figure it out from SQL.

@xuzhg
Copy link

xuzhg commented Jun 30, 2020

For the "bad" case as below:

http://localhost:5000/odata/BikeShop_GoodCategorys/CastProblem20200624.BikeShop_GoodCategory_NonRoot?$expand=CategoryChildren($select=ID,Version),Contents($select=ID,Version,CastProblem20200624.BikeShop_Good_Z3950Target/ISIL_Number,CastProblem20200624.BikeShop_Good__Local/Preferred_PropertyUri_For_BibliographicalRecord)

We have the follow linq "Debug view":

.New Microsoft.AspNet.OData.Query.Expressions.SelectExpandBinder+SelectAllAndExpand`1[CastProblem20200624.BikeShop_GoodCategory_NonRoot]()
{
    ModelID = .Constant<Microsoft.AspNet.OData.Query.Expressions.LinqParameterContainer+TypedLinqParameterContainer`1[System.String]>(Microsoft.AspNet.OData.Query.Expressions.LinqParameterContainer+TypedLinqParameterContainer`1[System.String]).TypedProperty,
    Instance = $$it,
    UseInstanceForProperties = True,
    Container = .New Microsoft.AspNet.OData.Query.Expressions.PropertyContainer+NamedPropertyWithNext0`1[System.Collections.Generic.IEnumerable`1[Microsoft.AspNet.OData.Query.Expressions.SelectExpandBinder+SelectSome`1[CastProblem20200624.BikeShop_GoodCategory_NonRoot]]]()
    {
        Name = "CategoryChildren",
        Value = .Call System.Linq.Enumerable.Select(
            ($$it .As CastProblem20200624.BikeShop_GoodCategory).CategoryChildren,
            .Lambda #Lambda1<System.Func`2[CastProblem20200624.BikeShop_GoodCategory_NonRoot,Microsoft.AspNet.OData.Query.Expressions.SelectExpandBinder+SelectSome`1[CastProblem20200624.BikeShop_GoodCategory_NonRoot]]>)
        ,
        Next0 = .New Microsoft.AspNet.OData.Query.Expressions.PropertyContainer+NamedProperty`1[System.Collections.Generic.IEnumerable`1[Microsoft.AspNet.OData.Query.Expressions.SelectExpandBinder+SelectSomeAndInheritance`1[CastProblem20200624.BikeShop_Good]]]()
        {
            Name = "Contents",
            Value = .Call System.Linq.Enumerable.Select(
                ($$it .As CastProblem20200624.BikeShop_GoodCategory).Contents,
                .Lambda #Lambda2<System.Func`2[CastProblem20200624.BikeShop_Good,Microsoft.AspNet.OData.Query.Expressions.SelectExpandBinder+SelectSomeAndInheritance`1[CastProblem20200624.BikeShop_Good]]>)
        }
    }
}

.Lambda #Lambda1<System.Func`2[CastProblem20200624.BikeShop_GoodCategory_NonRoot,Microsoft.AspNet.OData.Query.Expressions.SelectExpandBinder+SelectSome`1[CastProblem20200624.BikeShop_GoodCategory_NonRoot]]>(CastProblem20200624.BikeShop_GoodCategory_NonRoot $$it)
{
    .New Microsoft.AspNet.OData.Query.Expressions.SelectExpandBinder+SelectSome`1[CastProblem20200624.BikeShop_GoodCategory_NonRoot]()
    {
        ModelID = .Constant<Microsoft.AspNet.OData.Query.Expressions.LinqParameterContainer+TypedLinqParameterContainer`1[System.String]>(Microsoft.AspNet.OData.Query.Expressions.LinqParameterContainer+TypedLinqParameterContainer`1[System.String]).TypedProperty,
        Container = .New Microsoft.AspNet.OData.Query.Expressions.PropertyContainer+NamedPropertyWithNext0`1[System.Nullable`1[System.Guid]]()
        {
            Name = "ID",
            Value = (System.Nullable`1[System.Guid])($$it .As CastProblem20200624.BikeShop_GoodCategory).ID,
            Next0 = .New Microsoft.AspNet.OData.Query.Expressions.PropertyContainer+NamedProperty`1[System.Byte[]](){
                Name = "Version",
                Value = ($$it .As CastProblem20200624.BikeShop_GoodCategory).Version
            }
        }
    }
}

.Lambda #Lambda2<System.Func`2[CastProblem20200624.BikeShop_Good,Microsoft.AspNet.OData.Query.Expressions.SelectExpandBinder+SelectSomeAndInheritance`1[CastProblem20200624.BikeShop_Good]]>(CastProblem20200624.BikeShop_Good $$it)
{
    .New Microsoft.AspNet.OData.Query.Expressions.SelectExpandBinder+SelectSomeAndInheritance`1[CastProblem20200624.BikeShop_Good]()
    {
        ModelID = .Constant<Microsoft.AspNet.OData.Query.Expressions.LinqParameterContainer+TypedLinqParameterContainer`1[System.String]>(Microsoft.AspNet.OData.Query.Expressions.LinqParameterContainer+TypedLinqParameterContainer`1[System.String]).TypedProperty,
        InstanceType = .If (
            $$it .Is CastProblem20200624.BikeShop_Good__Local__BikeShop_BibliographicalRecordInventory
        ) {
            "CastProblem20200624.BikeShop_Good__Local__BikeShop_BibliographicalRecordInventory"
        } .Else {
            .If (
                $$it .Is CastProblem20200624.BikeShop_Good__Local__BikeShop
            ) {
                "CastProblem20200624.BikeShop_Good__Local__BikeShop"
            } .Else {
                .If (
                    $$it .Is CastProblem20200624.BikeShop_Good__Local
                ) {
                    "CastProblem20200624.BikeShop_Good__Local"
                } .Else {
                    .If (
                        $$it .Is CastProblem20200624.BikeShop_Good_Z3950Target
                    ) {
                        "CastProblem20200624.BikeShop_Good_Z3950Target"
                    } .Else {
                        "CastProblem20200624.BikeShop_Good"
                    }
                }
            }
        },
        Container = .New Microsoft.AspNet.OData.Query.Expressions.PropertyContainer+NamedPropertyWithNext2`1[System.Nullable`1[System.Guid]]()
        {
            Name = "ID",
            Value = (System.Nullable`1[System.Guid])$$it.ID,
            Next0 = .New Microsoft.AspNet.OData.Query.Expressions.PropertyContainer+NamedProperty`1[System.Byte[]](){
                Name = "Version",
                Value = $$it.Version
            },
            Next1 = .New Microsoft.AspNet.OData.Query.Expressions.PropertyContainer+NamedProperty`1[System.String](){
                Name = .If (
                    $$it .Is CastProblem20200624.BikeShop_Good_Z3950Target
                ) {
                    "ISIL_Number"
                } .Else {
                    null
                },
                Value = ($$it .As CastProblem20200624.BikeShop_Good_Z3950Target).ISIL_Number
            },
            Next2 = .New Microsoft.AspNet.OData.Query.Expressions.PropertyContainer+NamedProperty`1[System.String](){
                Name = .If (
                    $$it .Is CastProblem20200624.BikeShop_Good__Local
                ) {
                    "Preferred_PropertyUri_For_BibliographicalRecord"
                } .Else {
                    null
                },
                Value = ($$it .As CastProblem20200624.BikeShop_Good__Local).Preferred_PropertyUri_For_BibliographicalRecord
            }
        }
    }
}

For the "good" case as below:

http://localhost:5000/odata/BikeShop_GoodCategorys/CastProblem20200624.BikeShop_GoodCategory_NonRoot?$expand=CategoryChildren($select=ID,Version),Contents

We have the follow linq "Debug view":

.New Microsoft.AspNet.OData.Query.Expressions.SelectExpandBinder+SelectAllAndExpand`1[CastProblem20200624.BikeShop_GoodCategory_NonRoot]()
{
    ModelID = .Constant<Microsoft.AspNet.OData.Query.Expressions.LinqParameterContainer+TypedLinqParameterContainer`1[System.String]>(Microsoft.AspNet.OData.Query.Expressions.LinqParameterContainer+TypedLinqParameterContainer`1[System.String]).TypedProperty,
    Instance = $$it,
    UseInstanceForProperties = True,
    Container = .New Microsoft.AspNet.OData.Query.Expressions.PropertyContainer+NamedPropertyWithNext0`1[System.Collections.Generic.IEnumerable`1[Microsoft.AspNet.OData.Query.Expressions.SelectExpandBinder+SelectSome`1[CastProblem20200624.BikeShop_GoodCategory_NonRoot]]]()
    {
        Name = "CategoryChildren",
        Value = .Call System.Linq.Enumerable.Select(
            ($$it .As CastProblem20200624.BikeShop_GoodCategory).CategoryChildren,
            .Lambda #Lambda1<System.Func`2[CastProblem20200624.BikeShop_GoodCategory_NonRoot,Microsoft.AspNet.OData.Query.Expressions.SelectExpandBinder+SelectSome`1[CastProblem20200624.BikeShop_GoodCategory_NonRoot]]>)
        ,
        Next0 = .New Microsoft.AspNet.OData.Query.Expressions.PropertyContainer+NamedProperty`1[System.Collections.Generic.IEnumerable`1[Microsoft.AspNet.OData.Query.Expressions.SelectExpandBinder+SelectAll`1[CastProblem20200624.BikeShop_Good]]]()
        {
            Name = "Contents",
            Value = .Call System.Linq.Enumerable.Select(
                ($$it .As CastProblem20200624.BikeShop_GoodCategory).Contents,
                .Lambda #Lambda2<System.Func`2[CastProblem20200624.BikeShop_Good,Microsoft.AspNet.OData.Query.Expressions.SelectExpandBinder+SelectAll`1[CastProblem20200624.BikeShop_Good]]>)
        }
    }
}

.Lambda #Lambda1<System.Func`2[CastProblem20200624.BikeShop_GoodCategory_NonRoot,Microsoft.AspNet.OData.Query.Expressions.SelectExpandBinder+SelectSome`1[CastProblem20200624.BikeShop_GoodCategory_NonRoot]]>(CastProblem20200624.BikeShop_GoodCategory_NonRoot $$it)
{
    .New Microsoft.AspNet.OData.Query.Expressions.SelectExpandBinder+SelectSome`1[CastProblem20200624.BikeShop_GoodCategory_NonRoot]()
    {
        ModelID = .Constant<Microsoft.AspNet.OData.Query.Expressions.LinqParameterContainer+TypedLinqParameterContainer`1[System.String]>(Microsoft.AspNet.OData.Query.Expressions.LinqParameterContainer+TypedLinqParameterContainer`1[System.String]).TypedProperty,
        Container = .New Microsoft.AspNet.OData.Query.Expressions.PropertyContainer+NamedPropertyWithNext0`1[System.Nullable`1[System.Guid]]()
        {
            Name = "ID",
            Value = (System.Nullable`1[System.Guid])($$it .As CastProblem20200624.BikeShop_GoodCategory).ID,
            Next0 = .New Microsoft.AspNet.OData.Query.Expressions.PropertyContainer+NamedProperty`1[System.Byte[]](){
                Name = "Version",
                Value = ($$it .As CastProblem20200624.BikeShop_GoodCategory).Version
            }
        }
    }
}

.Lambda #Lambda2<System.Func`2[CastProblem20200624.BikeShop_Good,Microsoft.AspNet.OData.Query.Expressions.SelectExpandBinder+SelectAll`1[CastProblem20200624.BikeShop_Good]]>(CastProblem20200624.BikeShop_Good $$it)
{
    .New Microsoft.AspNet.OData.Query.Expressions.SelectExpandBinder+SelectAll`1[CastProblem20200624.BikeShop_Good](){
        ModelID = .Constant<Microsoft.AspNet.OData.Query.Expressions.LinqParameterContainer+TypedLinqParameterContainer`1[System.String]>(Microsoft.AspNet.OData.Query.Expressions.LinqParameterContainer+TypedLinqParameterContainer`1[System.String]).TypedProperty,
        Instance = $$it,
        UseInstanceForProperties = True
    }
}

@xuzhg
Copy link

xuzhg commented Jun 30, 2020

@smitpatel See the above linq expression (debug view), please let me know you need others.

@smitpatel
Copy link
Member

Can you get new ExpressionPrinter().Print(expression) output? ExpressionPrinter is a public class in EF which prints expression tree in readable format.

@xuzhg
Copy link

xuzhg commented Jun 30, 2020

@smitpatel

I use the following codes:

#if NETCOREAPP3_1
            string abc = new ExpressionPrinter().Print(projectionExpression);
            Console.WriteLine(abc);
#endif

here we are:

For "bad" case:

new SelectAllAndExpand<BikeShop_GoodCategory_NonRoot>{ 
    ModelID = TypedLinqParameterContainer<string>.TypedProperty, 
    Instance = $it, 
    UseInstanceForProperties = True, 
    Container = new NamedPropertyWithNext0<IEnumerable<SelectSome<BikeShop_GoodCategory_NonRoot>>>{ 
        Name = "CategoryChildren", 
        Value = ($it as BikeShop_GoodCategory).CategoryChildren
            .Select($it => new SelectSome<BikeShop_GoodCategory_NonRoot>{ 
                ModelID = TypedLinqParameterContainer<string>.TypedProperty, 
                Container = new NamedPropertyWithNext0<Nullable<Guid>>{ 
                    Name = "ID", 
                    Value = (Nullable<Guid>)($it as BikeShop_GoodCategory).ID, 
                    Next0 = new NamedProperty<byte[]>{ 
                        Name = "Version", 
                        Value = ($it as BikeShop_GoodCategory).Version 
                    }
                     
                }
                 
            }
            ), 
        Next0 = new NamedProperty<IEnumerable<SelectSomeAndInheritance<BikeShop_Good>>>{ 
            Name = "Contents", 
            Value = ($it as BikeShop_GoodCategory).Contents
                .Select($it => new SelectSomeAndInheritance<BikeShop_Good>{ 
                    ModelID = TypedLinqParameterContainer<string>.TypedProperty, 
                    InstanceType = ($it is BikeShop_Good__Local__BikeShop_BibliographicalRecordInventory) ? "CastProblem20200624.BikeShop_Good__Local__BikeShop_BibliographicalRecordInventory" : ($it is BikeShop_Good__Local__BikeShop) ? "CastProblem20200624.BikeShop_Good__Local__BikeShop" : ($it is BikeShop_Good__Local) ? "CastProblem20200624.BikeShop_Good__Local" : ($it is BikeShop_Good_Z3950Target) ? "CastProblem20200624.BikeShop_Good_Z3950Target" : "CastProblem20200624.BikeShop_Good", 
                    Container = new NamedPropertyWithNext2<Nullable<Guid>>{ 
                        Name = "ID", 
                        Value = (Nullable<Guid>)$it.ID, 
                        Next0 = new NamedProperty<byte[]>{ 
                            Name = "Version", 
                            Value = $it.Version 
                        }
                        , 
                        Next1 = new NamedProperty<string>{ 
                            Name = ($it is BikeShop_Good_Z3950Target) ? "ISIL_Number" : null, 
                            Value = ($it as BikeShop_Good_Z3950Target).ISIL_Number 
                        }
                        , 
                        Next2 = new NamedProperty<string>{ 
                            Name = ($it is BikeShop_Good__Local) ? "Preferred_PropertyUri_For_BibliographicalRecord" : null, 
                            Value = ($it as BikeShop_Good__Local).Preferred_PropertyUri_For_BibliographicalRecord 
                        }
                         
                    }
                     
                }
                ) 
        }
         
    }
     
}

for the "Good" case

new SelectAllAndExpand<BikeShop_GoodCategory_NonRoot>{ 
    ModelID = TypedLinqParameterContainer<string>.TypedProperty, 
    Instance = $it, 
    UseInstanceForProperties = True, 
    Container = new NamedPropertyWithNext0<IEnumerable<SelectSome<BikeShop_GoodCategory_NonRoot>>>{ 
        Name = "CategoryChildren", 
        Value = ($it as BikeShop_GoodCategory).CategoryChildren
            .Select($it => new SelectSome<BikeShop_GoodCategory_NonRoot>{ 
                ModelID = TypedLinqParameterContainer<string>.TypedProperty, 
                Container = new NamedPropertyWithNext0<Nullable<Guid>>{ 
                    Name = "ID", 
                    Value = (Nullable<Guid>)($it as BikeShop_GoodCategory).ID, 
                    Next0 = new NamedProperty<byte[]>{ 
                        Name = "Version", 
                        Value = ($it as BikeShop_GoodCategory).Version 
                    }
                     
                }
                 
            }
            ), 
        Next0 = new NamedProperty<IEnumerable<SelectAll<BikeShop_Good>>>{ 
            Name = "Contents", 
            Value = ($it as BikeShop_GoodCategory).Contents
                .Select($it => new SelectAll<BikeShop_Good>{ 
                    ModelID = TypedLinqParameterContainer<string>.TypedProperty, 
                    Instance = $it, 
                    UseInstanceForProperties = True 
                }
                ) 
        }
         
    }
     
}

@xuzhg
Copy link

xuzhg commented Jun 30, 2020

@smitpatel is the "$it" problem? It seems "$it" used in each level?

@smitpatel
Copy link
Member

Is BikeShop_Good__Local type mapped in EF Core model?
Probably, @ajcvickers can verify.

@henrikdahl8240
Copy link
Author

No, it was not and it is obviously a mistake. Its super class(es) and its sub classes are mapped, but not the class itself.

After mapping it, everything works fine, also in the real solution, which this is an excerpt of.

I am porting a solution from .NET Framework and EF 6.4 to .NET 5.0 and EF Core 5.0.

EF 6.4 had a different strategy as it could to some extent automatically discover and include some classes to the model. Therefore the issue did not occur in scope of .NET Framework and EF 6.4.

I think it's really difficult to spot such a case, for instance because the error message is of no help, except you can guess, that the null reference exception denotes that a mapping is missing, but it could denote all sorts of things. If you for instance try to $select an owned object, you get an excepton which tells, that either the owner must be included or you must use AsNoTracking(). This is quite easy to understand, however it's very annoying, that you cannot $select an owned type when tracking is being used and the owner is not being included.

Thank you for your assistance. It was really valuable to me. Perhaps others may benefit from this correlation, i.e. null reference exception and lack of mapping.

@xuzhg
Copy link

xuzhg commented Jun 30, 2020

@henrikdahl8240 Welcome. Glad to see that. Anyway, we also value from your questions, concerns. Thanks.

@henrikdahl8240
Copy link
Author

Thank you very much.

I think that it could be very valuable, if you would make a dedicated error message like e.g.:
Cannot get class from the repository of classes. Make sure classs is being mapped.

The new exception could be named something like "ClassNotFoundInTheRepositoryOfClassesException" or simply "ClassNotMappedException", but perhaps you have some other preferences for names.

You could make the exception System.NullReferenceException to be the inner exception for the dedicated exception.

Had there been such a dedicated error message, I would obviously have continued right away.

@smitpatel
Copy link
Member

The thing is, there is no way to know what is the cause of NullRef Exception. We evaluated user code which threw null ref. Just like any other user written code, there is only one reason for null ref but there is infinite reasons leading to a null ref.

@henrikdahl8240
Copy link
Author

OK. I thought the general business context of what is going on in the specific feature area could have told that. So it's a bit hard, of course.

So regarding "user code", you actually mean code in Microsoft OData because I don't think there's any of my code, which gets invoked in this case?

The lack of description in the error message just lets the user in a rather difficult situation as he obviously would like to make things to work well as efficiently and effective as possible.

@smitpatel
Copy link
Member

In the query EF sees ($it as BikeShop_Good__Local).Preferred_PropertyUri_For_BibliographicalRecord in the expression tree. It could be written by user or some library they are using generated it. We have no way of knowing that. For us that is the code which was passed to EF Core in expression tree and in order to generate the desired result, we have to either translate it or invoke it. Since "as Type" is not something which can be represented in server, we invoked it and it threw error.
Same would be the state if there some client function which can return null, followed by member access. I understand it is hard to know cause of error when you are using external libraries to create queries where you don't see actual query, but we don't have information to throw any better exception message.

@smitpatel smitpatel added the closed-no-further-action The issue is closed and no further action is planned. label Jul 28, 2020
@ajcvickers ajcvickers reopened this Oct 16, 2022
@ajcvickers ajcvickers closed this as not planned Won't fix, can't repro, duplicate, stale Oct 16, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
closed-no-further-action The issue is closed and no further action is planned. customer-reported
Projects
None yet
Development

No branches or pull requests

5 participants