简体   繁体   English

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

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

I have multiple records coming back from the DB, and I want to get the price from each row.我从数据库返回了多条记录,我想从每一行中获取价格。 However the price I want to select is dependent from the flags.但是我想要 select 的价格取决于标志。 I can do the following which brings back the numbers I want, however I would like a cleaner way of doing it.我可以执行以下操作来返回我想要的数字,但是我想要一种更简洁的方法。

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);

Assuming your Revised , Original , NonSentRevised , NonSentOriginal are simple types and of the same type.假设您的RevisedOriginalNonSentRevisedNonSentOriginal简单类型并且属于同一类型。 You can try the following:您可以尝试以下操作:

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

Note:笔记:

  • On a second thought we dont need anonymous class as we only need a single property再想想我们不需要匿名 class 因为我们只需要一个属性

  • As long as the "price" is simple types the code above should work for IQueryable instances只要“价格”是简单类型,上面的代码就应该适用于IQueryable实例

    when in doubt, run an SQL profiler to take a peek at the queries being generated如有疑问,请运行 SQL 探查器以查看正在生成的查询

You can try to use Ternary Operator to rewrite as a single query, let your condition in Select to judgment.你可以尝试使用三元运算符重写为单个查询,让你的条件在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);

another way, I would write a method to let the code clear另一种方式,我会写一个方法让代码清晰

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;
}

A simple ternary operation should get you what you need.一个简单的三元运算应该可以满足您的需求。

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

With sample data like this使用这样的示例数据

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

I got the following output我得到以下 output

200
500
1200
1500

** Edit ** ** 编辑 **

The SQL code generated by LINQ to SQL is as-expected and efficient 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]

If you are querying against objects (ie, against a IEnumerable<T> and not against a IQueryable<T> ), you can use pattern matching:如果您正在查询对象(即,针对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
    });

This uses a tuple pattern as a special case of a positional pattern.这使用元组模式作为位置模式的特例。

See also:也可以看看:

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

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