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);
CodePudding user response:
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;
}
CodePudding user response:
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
instanceswhen in doubt, run an SQL profiler to take a peek at the queries being generated
CodePudding user response:
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]
CodePudding user response:
If you are querying against objects (i.e., 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: