我的代码在下面,在 .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
结果将包含 Category 或 Warehouse 的一些 null,在 .NET Core 3.1 中,默认值将分配给对象。 但是在 .NET 7 中运行时,它会在运行时抛出异常
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)
整个项目有很多这样的地方,手动检查null几乎是不可能完成的任务,请谁能帮我解决这个问题,就像如何重新打开“设置为null时的默认值”一样.NET 3.1 以前做过。谢谢。
您需要显式定义空值。 试试这个:
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();
更新:我忽略了你问题的最后一部分。 如果要禁用文件中的可为空功能,可以将
#nullable disable
放在文件顶部。要在整个项目范围内应用它,请在您的 .csproject 中设置此选项<Nullable>enable</Nullable>
.
在.NET Core 3.1中,当你使用DefaultIfEmpty()方法连接两个表时,如果结果为null,则会为该对象分配一个默认值。但是,在 .NET 7 中,这种行为发生了变化,您需要显式检查空值。
解决这个问题的一种方法是使用空条件运算符 ?。访问连接操作返回的对象的属性。此运算符允许您将多个 null 检查链接在一起,因此您可以安全地访问嵌套属性而不必担心 null 值。
这是一个示例,说明如何修改 LINQ 查询以使用 null 条件运算符:
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,
CategoryName = c?.Name,
WarehouseName = wh?.Name
};
在这个例子中,我们使用空条件运算符 ?。访问类别和仓库对象的名称属性。如果对象为 null,则运算符返回 null 而不是抛出异常。
通过以这种方式使用空条件运算符,您可以安全地访问连接对象的属性,而不必担心空值。