My legacy code on net core 3.1 is throwing exception when moving to .NET 7 with message "Nullable object must have a value"
Asked Answered
T

3

5

My code is below, working fine in .NET Core 3.1:

// dto is search criteria passing from outside
var query = from p in dbContext.Products.Where(p => dto.Ids.Contains(p.Id))
            from c in dbContext.Categorys.Where(c => c.Id == p.CategoryId).DefaultIfEmpty()
            from wh in dbContext.Warehouses.Where(wh => wh.Id == p.WarehouseId).DefaultIfEmpty()
            select new 
            {
                Product = p,
                Category = c,
                Warehouse = wh
            };
`var products = await query.ToListAsync();` // this line will throw exception

the result will contains some null for Category or Warehouse, in .NET Core 3.1 the default value will be assign to the object. But when running in .NET 7, it throws exception at run-time

System.InvalidOperationException with message "Nullable object must have a value."
2023-03-29T10:34:25.7553873Z              at lambda_method3977(Closure, QueryContext, ValueBuffer)
2023-03-29T10:34:25.7555036Z              at Microsoft.EntityFrameworkCore.InMemory.Query.Internal.InMemoryShapedQueryCompilingExpressionVisitor.QueryingEnumerable`1.Enumerator.MoveNextHelper()
2023-03-29T10:34:25.7555635Z              at Microsoft.EntityFrameworkCore.InMemory.Query.Internal.InMemoryShapedQueryCompilingExpressionVisitor.QueryingEnumerable`1.Enumerator.MoveNextAsync()
2023-03-29T10:34:25.7559660Z              at System.Runtime.CompilerServices.ConfiguredCancelableAsyncEnumerable`1.Enumerator.MoveNextAsync()
2023-03-29T10:34:25.7560134Z              at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListAsync[TSource](IQueryable`1 source, CancellationToken cancellationToken)
2023-03-29T10:34:25.7560408Z              at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListAsync[TSource](IQueryable`1 source, CancellationToken cancellationToken)


There are a lot of places like this through the whole project, check null manually almost an impossible task, can anyone help me give a solution for this please, just like how to turn back on the "setting default value when null" same as .NET 3.1 did before. Thank you.

Thermoluminescence answered 29/3, 2023 at 13:22 Comment(4)
Is one or more of your value-type properties nullable, e.g. p.Id?Dvina
Won't p, c, and wh all be IEnumerable<> types and not individual objects?Hydrodynamics
Is there a good reason why you aren't just using navigation properties? dbContext.Products.Where(...).Include(p => p.Category).Include(p => p.Warehouse)Illtreat
this is a legacy code, there are thousands of places like this, I'm trying to upgrade to .net 7.Thermoluminescence
K
3

You need to define null values explicitly. Try this:

var query = from p in dbContext.Products .Where(p => dto.Ids.Contains(p.Id)) 
            from c in dbContext.Categorys.Where(c => c.Id == p.CategoryId).DefaultIfEmpty() 
            from wh in dbContext.Warehouses.Where(wh => wh.Id == p.WarehouseId).DefaultIfEmpty() 
            select new { 
                Product = p, 
                Category = c == null ? null : c, 
                Warehouse = wh == null ? null : wh 
                }; 

var products = await query.ToListAsync();

Update: I overlooked the last section of your question. If you want to disable the nullable feature in a file, you can put #nullable disable on top of your file. To apply it project-wide, set this option in your .csproject <Nullable>enable</Nullable>.

Krol answered 2/4, 2023 at 16:12 Comment(2)
thanks Enz, i tried to set <Nullable>disable</Nullable> to every single projects, but still got same error.Thermoluminescence
I believe those options have added in C# 8, is it possible to switch to that version?Krol
A
3

If you're porting legacy code try to set <Nullable>False</Nullable> in the projects.

See Nullable reference types (C# reference) and Tutorial: Express your design intent more clearly with nullable and non-nullable reference types.

Alkahest answered 2/4, 2023 at 17:4 Comment(2)
Maybe you meant the <Nullable>disable</Nullable>, I tried the that also got same problem, try with #nullable disable at the start of file as well, still no luckThermoluminescence
Sorry for the late response, you're right the right value is disable. I have a last suggestion. Since the problem seems to be with EF dbcontext, I suggest to try to generate a migration (with the Nullable set to disable in the projects), to see if some changes to db schema is generated. In this way you can check if there is some property, I expect that some column is mapped with some not null constraint, and eventually you could undo the migration and configure this properties to be nullable in mapping.Alkahest
S
0

Have you tried specifying that the types are nullable explicitly like this?

select new 
{
    Product = p,
    Category = (CategoryType?) c,
    Warehouse = (WarehouseType?) wh
};
Spiracle answered 7/4, 2023 at 10:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.