LINQ get Max value from list - linq

I have the following table:
ID Amt Received
-- ---- --------
2 55 N
2 88 Y
2 44 N
3 5 N
3 9 N
4 5 N
5 33 Y
6 43 N
7 54 N
var result = (from rs in db.Exp
where rs.ID == id
&& rs.Received == true
select rs).Max().Any();
Given an ID, I need to find the max Amt for a given id and then check if it is Y, if so, return true else return false.

This should do it;
db.Exp.
Where(x => x.ID == id).
OrderByDescending(x => x.Amt).
Take(1).
Any(x => x.Received == "Y");

Unfortunately LINQ doesn't provide a "max by an attribute" method. MoreLINQ does with its MaxBy operator, but that can't be translated into SQL of course. So if this is a LINQ to SQL (or whatever) query, you'll need a different approach. If it's already LINQ to Objects, however:
return db.Exp.Where(rs => rs.ID == id)
.MaxBy(rs => rs.Amt)
.Received;
Note that this is doing what the words of your question ask:
Out of the records with the given ID...
Find the one with the highest amount...
And check the value of Received
This is not the same as:
Out of the records with the given ID where received is true...
Find the one with the highest amount
Also note that this will throw an exception if there are no records with that ID.
If you want to do it in LINQ to SQL etc, you'd probably be best off with an ordering:
var highest = db.Exp.Where(rs => rs.ID == id)
.OrderByDescending(rs => rs.Amt)
.FirstOrDefault();
return highest != null && highest.Received;
You don't want to do this if you're using LINQ to Objects, as it will order all the results, when you only want to find the result with the highest amount.

You need to tell it what you want the Max of.
var result =
(from rs in db.Exp
where rs.ID == id && rs.Received
select rs)
.Max(row => row.Amt) == Y;
And you don't need the .Any() at all

// "I need to find the max Amt for a given id..."
var elementWithMaxAmount =
db.Exp
.Where(x => x.ID == id)
.OrderByDescending(x => x.Amount)
.FirstOrDefault();
// "... and then check if it is Y"
var result = (elementWithMaxAmount != null &&
elementWithMaxAmount.Received == "Y");

Related

linq to entity,How does the where clause use ?: Expression

TAB_XXX and TAB_XXX_details are one-to-many relationships, I need to query the two tables, however, we need to be filtered TAB_XXX_details。
The code is as follows:
var qu = from c in db.TAB_XXX.Where(n => n.DELETE_MARK == false)
let dets = c.TAB_XXX_DETAILS.Where(n => condition.SaleType.HasValue ? n.SALE_TYPE == (decimal)condition.SaleType : 1 == 1)
select new
{
c,
dets
};
Condition.SaleType is number?, if the condition.SaleType is a valid number, such as 1, 2, 3 ... I want to filter the child record based on these numbers; when the condition.SaleType is null, I want to query TAB_XXX and all its child records;
How do I modify the where clause?
Thank you for your answer!
Since 1 == 1 is always true, your condition boils down to this:
let dets = c.TAB_XXX_DETAILS
.Where(n => !condition.SaleType.HasValue || n.SALE_TYPE == condition.SaleType.Value)
Essentially, you want to return all rows when condition.SaleType does not have value; otherwise, you make a comparison to condition.SaleType.Value.

LINQ to Entities GroupBy, OrderByDescending, FirstOrDefault when

I have a following problem with LINQ to Entities. I am selecting records from DB, group them and then order them by Id descending. Then i want to select First item but only if Quantity is != 0. I think because i have to use FirstOrDefault i am getting wrong results but am not sure how to correct it.
DB
Now this query will give me ID's 2 and 1 grouped and 4 "grouped". What i need is to select FIRST items only if Quantity is != 0 and am not sure how to get that.
data = DbContext.Items.Where(x.WarehouseId == 1)
.GroupBy(x => x.ItemCode, (key, g) => g.OrderByDescending(y => y.Id).FirstOrDefault())
.OrderBy(parameters.SortExpression)
.Skip(parameters.Start)
.Take(parameters.Length);
If WarehouseID is 1 i need to get only row with ID 4 back. Any help is appreciated.
Edit: First i need to groupBy ItemCode, then i will have two groups for my case above. That's 1 and 2 for first group, and 4 for second group. Then i order them by Id descending and i get (2, 1), (4). Then i need to select first from group but only if Quantity is != 0. If Quantity is zero i don't want to select anything from a group.
Image to clarify what i need. I'm stuck on last step Take FristFrom each group only if quantity is != 0
EDIT: This is, what you want to do:
var data = DbContext.Items
.Where(p => p.WarehouseId == 1)
.GroupBy(p => p.ItemCode, (key, items) => new { Key = key, Items = items, ItemsCountWithQuantityZero = items.Where(p => p.Quantity == 0).Count() })
.Where(p => p.ItemsCountWithQuantityZero == 0)
.Select(p => p.Items.OrderByDescending(q => q.Id).First());

How to get two sums from a linq query

Summary
I have a list of Transactions. Using Linq, I want to get a sum of the Cost and sum of the Quantity from this list in one query.
Grouping
My first thought is to use grouping - but I don't really have a key that I want to group on, I want just one group with the results from the whole list. So, I happen to have a property called "Parent" that will be the same for all of the transactions, so I'm using that to group on:
var totalCostQuery =
(from t in Transactions
where t.Status != GeneralStoreTransactionStatus.Inactive &&
(t.Type == GeneralStoreTransactionType.Purchase ||
t.Type == GeneralStoreTransactionType.Adjustment)
group t by t.Parent into g
select new
{
TotalCost = g.Sum(t => t.Cost.GetValueOrDefault()),
TotalQuantity = g.Sum(t => t.Quantity.GetValueOrDefault())
});
Grouping by t.Parent seems like it could be wrong. I really don't want to group at all, I just want the sum of t.Quantity and sum of t.Cost.
Is that the correct way to get a sum of two different properties or can it be done in a different way.
Assuming this is Linq to SQL or Entity Framework, you can do that:
var totalCostQuery =
(from t in Transactions
where t.Status != GeneralStoreTransactionStatus.Inactive &&
(t.Type == GeneralStoreTransactionType.Purchase ||
t.Type == GeneralStoreTransactionType.Adjustment)
group t by 1 into g
select new
{
TotalCost = g.Sum(t => t.Cost),
TotalQuantity = g.Sum(t => t.Quantity)
});
Note that you don't need to use GetValueOrDefault, null values will be ignored in the sum.
EDIT: not sure this works with Linq to NHibernate though...
Note that if you're using Linq to objects, the solution above won't be efficient, because it will enumerate each group twice (once for each sum). In that case you can use Aggregate instead:
var transactions =
from t in Transactions
where t.Status != GeneralStoreTransactionStatus.Inactive &&
(t.Type == GeneralStoreTransactionType.Purchase ||
t.Type == GeneralStoreTransactionType.Adjustment)
select t;
var total =
transactions.Aggregate(
new { TotalCost = 0.0, TotalQuantity = 0 },
(acc, t) =>
{
TotalCost = acc.TotalCost + t.Cost.GetValueOrDefault(),
TotalQuantity = acc.TotalQuantity + t.Quantity.GetValueOrDefault(),
});

Removing values from a returned linq query

HI there I am hoping for some help with a query I have.
I have this query
var group =
from r in CustomerItem
group r by r.StoreItemID into g
select new { StoreItemID = g.Key,
ItemCount = g.Count(),
ItemAmount = Customer.Sum(cr => cr.ItemAmount),
RedeemedAmount = Customer.Sum(x => x.RedeemedAmount)
};
I am returning my results to a list so I can bind it listbox.
I have a property called EntryType which is an int. There are 2 available numbers 1 or 2
Lets say I had 3 items that my query is working with
2 of them had the EntryType = 1 and the 3rd had EntryType2. The first records had a ItemAmount of 55.00 and the 3rd had a ItemAmount of 50.00
How can I group using something simlar to above but minus the ItemAmount of 50.00 from the grouped amount to return 60.00?
Any help would be great!!
It's not really clear what the question is - are you just trying to ignore all items with an entry type of 2? To put it another way, you only want to keep entries with an entry type of 1? If so, just add a where clause:
var group = from r in CustomerItem
where r.EntryType == 1
group r by r.StoreItemID into g
select new {
StoreItemID = g.Key, ItemCount = g.Count(),
ItemAmount = Customer.Sum(cr => cr.ItemAmount),
RedeemedAmount = Customer.Sum(x => x.RedeemedAmount)
};
Change ItemAmount = ... to:
ItemAmount =
g.Where(x => x.EntryType == 1).Sum(cr => cr.ItemAmount) -
g.Where(x => x.EntryType == 2).Sum(cr => cr.ItemAmount),
I changed Customer to g because this seems to be an error, but it's not clear to me from your question what you mean here, so maybe this change is not what you want.
A slightly more concise method is to use test the entry type in the sum and use the ternary operator to choose whether to add the positive or negative value:
ItemAmount = g.Sum(cr => cr.EntryType == 1 ? cr.ItemAmount : -cr.ItemAmount),
This gives the value of 60.00 as you required.

LINQ - Return Value From Field With A Max Value if No Rows Found

I have a table like this...
ID Description LowThreshold HighThreshold
1 BAD 0.0 .69
2 MEETS .70 .89
3 GOOD .90 2
The object here is to write a LINQ query that will select the right Description based on a given decimal. For instance .75 is between .70 and .89, so it would return “MEETS”. BUT, the kicker is, if the Number is higher than all the ranges, automatically return the Description for the record with the highest HighThreshold. So, if I pass in 5, I should get “GOOD” returned.
I have this so far, but it errors out with scores higher than 2, obviously:
private string GetEvaluationDescription (decimal score)
{
string evaluationText = myContext.PerformanceRanges.Where
(e =>
e.LowThreshold <= score
&&
e.HighThreshold >= score
)
.Select(eval => eval.Description).First().ToString();
}
I'd like to accomplish this with just this one query, but my imagination isn't getting me there. I attempted what I found in this post but couldn't get it to work
What about this:
var range = myContext.PerformanceRanges
.SingleOrDefault(e=>e.LowThreshold <= score && e.HighThreshold >= score)??
PerformanceRanges.Single(
e=>e.HighThreshold == PerformanceRanges
.Max(p=> p.HighThreshold)
);
string evaluationText = range.Description;
The range query will select the element that matches with the Thereshold ranges, and if the value is greater (the first query will return null), it will select the greatest range.
What about this:
string evaluationText = myContext.PerformanceRanges.Where
(e =>
(e.LowThreshold <= score
&&
e.HighThreshold >= score) ||
(e.HighThreshold ==
myContext.PerformanceRanges.Max (
x => x.HighThreshold)
&& score > e.HighThreshold )
)
.Select(eval => eval.Description).First().ToString();

Resources