Linq 查询表达式中的空检查
Null check in Linq query expression
我有一个基于工作方法的查询,如下所示:
string param = request.QRBarang.Split('~')[1];
var a = await _db.A.FirstOrDefaultAsync(a => a.IdA == param);
var b = await _db.B.FirstOrDefaultAsync(b => b.IdB1 == a.IdA);
var c = await _db.C.FirstOrDefaultAsync(c => c.IdC1 == b.IdB2);
var d = c != null
? await _db.D.FirstOrDefaultAsync(d => d.IdD == c.IdC2)
: null;
var dto = new DTOFin { ...};
我仍在学习 LINQ 并尝试将语法转换为查询表达式,但当 c 的值为 null 时总是出错。
这是我的尝试:
var dto = (from a in _db.A
join b in _db.B on a.IdA equals b.IdB1
join c in _db.C on b.IdB2 equals c.IdC1
join d in _db.D on c.IdC2 equals d.IdD
where a.IdA == param && object.Equals(c.IdC2, d.IdD)
select new DTOFin { ...}).FirstOrDefaultAsync();
我也试过使用join c in _db.C on b.IdB2 equals c?.IdC1
但是产生了
Error CS8072 An expression tree lambda may not contain a null propagating operator.
查询表达式中的第一个等价语法应该怎么写?
假设您正确配置了导航属性,那么这应该可以工作:
(我注意到 EF6 和 EF Core 的脚手架模板(用于从现有数据库自动生成实体 类)已经为您执行此操作。)
(此外,我真的不喜欢 C# 的关键字式 Linq 表达式,因为为了做几乎任何事情,您都需要附加 Linq 扩展方法,这在美学上与关键字式表达式冲突。我可以'老实说,现在想不出有什么理由使用关键字样式的 Linq 表达式。
我假设 _db
是你的 DbContext
。
using System.Linq;
using System.Data.Entity; // for EF6
using Microsoft.EntityFrameworkCore.Query; // for EF Core
A a = await _db.A
.Include( a => a.B )
.Include( a => a.B.C )
.Include( a => a.B.C.D )
.Where( a => a.IdA == param )
.SingleOrDefaultAsync();
// b, c, and d can then be gotten from A:
B b = a.B;
C c = a.B.C;
D d = a.B.C?.D; // It looks like A.B and B.C are INNER JOIN while C.D is LEFT OUTER JOIN. Linq will use the correct JOIN type (INNER, LEFT, etc) based on your model configuration. You cannot tell from the query alone.
return new DTOFin() { ... };
如果您没有设置导航属性(您应该...),那么您可以手动进行连接 - 但值得注意的是 更粗糙 因为 Linq 的 .Join
方法从未打算直接使用,因为您应该使用导航属性来代替。
- 请注意,因为此 Linq 查询与 Entity Framework 一起使用,这意味着您的查询必须在 SQL 中可表示...
- 这意味着某些限制适用:例如不使用
?.
运算符 - 这是您的问题。
- 其他限制包括无法使用您自己的自定义谓词函数(除非它们也是
Expression<Func<>>
),因为您不能只将 C# 代码放入 SQL 查询中。
我相信下面的查询 应该 有效,但在不了解更多关于您的 EF 模型配置和数据库设计的情况下我不能肯定地说 - 您没有在您的开题 post.
var a_b_c_d = await _db.A
.Join( _db.B, a => a.IdA , b => b.IdB1, ( a , b ) => new { a, b } )
.Join( _db.C, a_b => a_b.b.IdB2 , c => c.IdC1, ( a_b , c ) => new { a_b.a, a_b.b, c } )
.Join( _db.D, a_b_c => a_b_c.c.IdC2, d => d.IdD , ( a_b_c, d ) => new { a_b_c.a, a_b_c.b, a_b_c.c, d } )
.Where( a_b_c_d => a_b_c_d.a.IdA == param )
.SingleOrDefaultAsync();
A a = a_b_c_d.a;
B b = a_b_c_d.b;
C c = a_b_c_d.c;
D d = a_b_c_d.d;
return new DTOFin() { ... };
我认为这可以通过使用 LINQ 查询语法来实现。
var dto = (from a in _db.A
join b in _db.B on a.IdA equals b.IdB1
join c in _db.C on b.IdB2 equals c.IdC1 into cTemp
from cT in cTemp.DefaultIfEmpty()
join d in _db.D on c.IdC2 equals d.IdD into dTemp
from dT in dTemp.DefaultIfEmpty()
where a.IdA == param
select new DTOFin
{
...
}).FirstOrDefaultAsync();
您可以 select c 和 d table 来自 cT 和 dT 变量的值。
我有一个基于工作方法的查询,如下所示:
string param = request.QRBarang.Split('~')[1];
var a = await _db.A.FirstOrDefaultAsync(a => a.IdA == param);
var b = await _db.B.FirstOrDefaultAsync(b => b.IdB1 == a.IdA);
var c = await _db.C.FirstOrDefaultAsync(c => c.IdC1 == b.IdB2);
var d = c != null
? await _db.D.FirstOrDefaultAsync(d => d.IdD == c.IdC2)
: null;
var dto = new DTOFin { ...};
我仍在学习 LINQ 并尝试将语法转换为查询表达式,但当 c 的值为 null 时总是出错。 这是我的尝试:
var dto = (from a in _db.A
join b in _db.B on a.IdA equals b.IdB1
join c in _db.C on b.IdB2 equals c.IdC1
join d in _db.D on c.IdC2 equals d.IdD
where a.IdA == param && object.Equals(c.IdC2, d.IdD)
select new DTOFin { ...}).FirstOrDefaultAsync();
我也试过使用join c in _db.C on b.IdB2 equals c?.IdC1
但是产生了
Error CS8072 An expression tree lambda may not contain a null propagating operator.
查询表达式中的第一个等价语法应该怎么写?
假设您正确配置了导航属性,那么这应该可以工作:
(我注意到 EF6 和 EF Core 的脚手架模板(用于从现有数据库自动生成实体 类)已经为您执行此操作。)
(此外,我真的不喜欢 C# 的关键字式 Linq 表达式,因为为了做几乎任何事情,您都需要附加 Linq 扩展方法,这在美学上与关键字式表达式冲突。我可以'老实说,现在想不出有什么理由使用关键字样式的 Linq 表达式。
我假设 _db
是你的 DbContext
。
using System.Linq;
using System.Data.Entity; // for EF6
using Microsoft.EntityFrameworkCore.Query; // for EF Core
A a = await _db.A
.Include( a => a.B )
.Include( a => a.B.C )
.Include( a => a.B.C.D )
.Where( a => a.IdA == param )
.SingleOrDefaultAsync();
// b, c, and d can then be gotten from A:
B b = a.B;
C c = a.B.C;
D d = a.B.C?.D; // It looks like A.B and B.C are INNER JOIN while C.D is LEFT OUTER JOIN. Linq will use the correct JOIN type (INNER, LEFT, etc) based on your model configuration. You cannot tell from the query alone.
return new DTOFin() { ... };
如果您没有设置导航属性(您应该...),那么您可以手动进行连接 - 但值得注意的是 更粗糙 因为 Linq 的 .Join
方法从未打算直接使用,因为您应该使用导航属性来代替。
- 请注意,因为此 Linq 查询与 Entity Framework 一起使用,这意味着您的查询必须在 SQL 中可表示...
- 这意味着某些限制适用:例如不使用
?.
运算符 - 这是您的问题。 - 其他限制包括无法使用您自己的自定义谓词函数(除非它们也是
Expression<Func<>>
),因为您不能只将 C# 代码放入 SQL 查询中。
- 这意味着某些限制适用:例如不使用
我相信下面的查询 应该 有效,但在不了解更多关于您的 EF 模型配置和数据库设计的情况下我不能肯定地说 - 您没有在您的开题 post.
var a_b_c_d = await _db.A
.Join( _db.B, a => a.IdA , b => b.IdB1, ( a , b ) => new { a, b } )
.Join( _db.C, a_b => a_b.b.IdB2 , c => c.IdC1, ( a_b , c ) => new { a_b.a, a_b.b, c } )
.Join( _db.D, a_b_c => a_b_c.c.IdC2, d => d.IdD , ( a_b_c, d ) => new { a_b_c.a, a_b_c.b, a_b_c.c, d } )
.Where( a_b_c_d => a_b_c_d.a.IdA == param )
.SingleOrDefaultAsync();
A a = a_b_c_d.a;
B b = a_b_c_d.b;
C c = a_b_c_d.c;
D d = a_b_c_d.d;
return new DTOFin() { ... };
我认为这可以通过使用 LINQ 查询语法来实现。
var dto = (from a in _db.A
join b in _db.B on a.IdA equals b.IdB1
join c in _db.C on b.IdB2 equals c.IdC1 into cTemp
from cT in cTemp.DefaultIfEmpty()
join d in _db.D on c.IdC2 equals d.IdD into dTemp
from dT in dTemp.DefaultIfEmpty()
where a.IdA == param
select new DTOFin
{
...
}).FirstOrDefaultAsync();
您可以 select c 和 d table 来自 cT 和 dT 变量的值。