繁体   English   中英

C# linq 多个不同标志的记录返回单个列表

[英]C# linq multiple records with different flags to return to a single list

我从数据库返回了多条记录,我想从每一行中获取价格。 但是我想要 select 的价格取决于标志。 我可以执行以下操作来返回我想要的数字,但是我想要一种更简洁的方法。

var one = Records.Where(x => x.HasBeenSent && x.Revised != 0).Select(x => x.Revised);
var two = Records.Where(x => x.HasBeenSent && x.Revised == 0).Select(x => x.Original);
var three = Records.Where(x => !x.HasBeenSent && x.NonSentRevised != 0).Select(x => x.NonSentRevised);
var four = Records.Where(x => !x.HasBeenSent && x.NonSentRevised == 0).Select(x => x.NonSentOriginal);

假设您的RevisedOriginalNonSentRevisedNonSentOriginal简单类型并且属于同一类型。 您可以尝试以下操作:

var prices = Records.Select(x =>
     (x.HasBeenSent ? 
         (x.Revised != 0 ? x.Revised : x.Original)
            : (x.NonSentRevised != 0 ? x.NonSentRevised
                 : x.NonSentOriginal )))

笔记:

  • 再想想我们不需要匿名 class 因为我们只需要一个属性

  • 只要“价格”是简单类型,上面的代码就应该适用于IQueryable实例

    如有疑问,请运行 SQL 探查器以查看正在生成的查询

你可以尝试使用三元运算符重写为单个查询,让你的条件在Select来判断。

var one = Records.Where(x => 
   (x.HasBeenSent && x.Revised != 0) ||
   (x.HasBeenSent && x.Revised == 0) ||
   (x => !x.HasBeenSent && x.NonSentRevised != 0) ||
   (!x.HasBeenSent && x.NonSentRevised == 0) 
).Select(x => (x.HasBeenSent && x.Revised != 0) ? x.Revised : 
(x.HasBeenSent && x.Revised == 0) ? x.Original : 
(x => !x.HasBeenSent && x.NonSentRevised != 0) ?  x.NonSentRevised:
(!x.HasBeenSent && x.NonSentRevised == 0) x.NonSentOriginal : 0);

另一种方式,我会写一个方法让代码清晰

var one = Records.Where(x => 
   (x.HasBeenSent && x.Revised != 0) ||
   (x.HasBeenSent && x.Revised == 0) ||
   (x => !x.HasBeenSent && x.NonSentRevised != 0) ||
   (!x.HasBeenSent && x.NonSentRevised == 0) 
).Select(GetPrice);


decimal GetPrice(Record x){
    if(HasBeenSent){
        if(x.Revised != 0)
            return x.Revised;
        else 
            return x.Original;
    }
    
    if(!x.HasBeenSent){
        if(x.NonSentRevised != 0)
            return x.NonSentRevised;
        else 
            return  x.NonSentOriginal;
    }
    return 0;
}

一个简单的三元运算应该可以满足您的需求。

var result = 
    from x in Records
    select 
        x.HasBeenSent
            ? (x.Revised != 0 ? x.Revised : x.Original) 
            : (x.NonSentRevised != 0 ? x.NonSentRevised : x.NonSentOriginal);

使用这样的示例数据

HasBeenSent Original Revised NonSentOriginal NonSentRevised
1   100     200      300     400             200
1   500     0        700     800             500
0   900     1000     1100    1200            1200
0   1300    1400     1500    0               1500

我得到以下 output

200
500
1200
1500

** 编辑 **

LINQ到SQL生成的SQL代码符合预期,高效

-- Region Parameters
DECLARE @p0 Int = 0
DECLARE @p1 Int = 0
-- EndRegion
SELECT 
    (CASE 
        WHEN [x].[HasBeenSent] = 1 THEN 
            (CASE 
                WHEN [x].[Revised] <> @p0 THEN [x].[Revised]
                ELSE [x].[Original]
             END)
        WHEN [x].[NonSentRevised] <> @p1 THEN [x].[NonSentRevised]
        ELSE [x].[NonSentOriginal]
     END) AS [value]
FROM [Records] AS [x]

如果您正在查询对象(即,针对IEnumerable<T>而不是针对IQueryable<T> ),您可以使用模式匹配:

var result = Records
    .Select(x => (x.HasBeenSent, x.Revised, x.NonSentRevised) switch {
        (true,  not 0, _)     => x.Revised,
        (true,  0,     _)     => x.Original,
        (false, _,     not 0) => x.NonSentRevised,
        (false, _,     0)     => x.NonSentOriginal
    });

这使用元组模式作为位置模式的特例。

也可以看看:

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM