简体   繁体   中英

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. 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. 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

  • As long as the "price" is simple types the code above should work for IQueryable instances

    when in doubt, run an SQL profiler to take a peek at the queries being generated

You can try to use Ternary Operator to rewrite as a single query, let your condition in Select to judgment.

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

200
500
1200
1500

** Edit **

The SQL code generated by LINQ to SQL is as-expected and efficient

-- 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:

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:

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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