How to calculate sum() column from dynamic list? - linq

I have a dynamic list that is given below;
var CashReceiptDailyCollectionDetails = new List<dynamic>();
In the above list having TotalAmount column; How to calculate Sum of TotalAmount by using linq query from dynamic list. I was tried like below query; but it gives object referance error.
CashReceiptDailyCollectionDetails.Sum(x => Convert.ToDecimal(x.TotalAmount))

decimal holdingNum = -1;
var decimalsSums = CashReceiptDailyCollectionDetails.
Select(o => o != null ?( string.IsNullOrEmpty(o.ToString()) == false?
(decimal.TryParse(o.ToString(), out holdingNum) == true ?
holdingNum : 0) : 0):0).Sum();

Related

How to compare IEnumerable<string> for null in Linq query

For the following query:
var result = from sch in schemeDashboard
join exp in Expenditure on sch.schemeId equals exp.SchemeCode
into SchExpGroup
where sch.SectorDepartmentId == selectedDepartmentId &&
sch.YearCode == StateManager.CurrentYear
orderby sch.ADPId
select new
{
ModifiedAmounts = SchExpGroup.Select(a => a.ModifiedAmounts),
ProjectName = sch.schemeName,
ADPNo = sch.ADPId,
Allocation = sch.CurrentAllocation,
Expenditures = from expend in SchExpGroup
where expend.YearCode == StateManager.CurrentYear &&
expend.DepartmentId == selectedDepartmentId &&
InvStatus.Contains(expend.Status)
orderby expend.ADPId
group expend by expend.InvoiceId
};
I want to filter the above query on a condition so that result gives only those records where "ModifiedAmounts" are not null. I have tried as follow:
if (rbList2.SelectedIndex == 6)
{
result = result.Where(a => a.ModifiedAmounts != null));
}
but this gives error as:
Cannot compare elements of type
'System.Collections.Generic.IEnumerable`1'. Only primitive types,
enumeration types and entity types are supported.
Any suggestions as I am lost as how to rephrase the filtered query.
I think the problem is that ModifiedAmounts will never be null. Select will return an empty list. Unless SchExpGroup is null in which case you will get a null reference exception.
Try changing your code to
result = result.Where(a => a.ModifiedAmounts.Any());
if (rbList2.SelectedIndex == 6)
{
result = result.Where(a => a.!ModifiedAmounts.Any());
}

How can I define a List to add results of a query in a loop?

I have an array filled with long type values and for each value in the array I need to implement a query. I used foreach loop as you can see from the code below:
var result;
foreach(long id in PrdIdArr)
{
var mainQuery = (from o in db.OPERATIONs
join u in db.UNITs on o.OP_UNIT_ID equals u.UNIT_ID into smt
from s in smt
join x in db.XIDs on s.UNIT_ID equals x.UNIT_ID
where o.OP_OT_CODE == OtCode
where x.IDTYP_CD == "BSN"
where s.START_PRD_ID == id
where o.OP_UPD_DATE >= _StartDate
where o.OP_UPD_DATE <= _EndDate
select new
{
o.OP_ID,
o.OP_UPD_DATE,
x.EXTERNAL_ID,
o.OP_OS_CODE,
o.OP_START,
o.OP_ST_STATION,
s.START_PRD_ID
}).Take(_RowNumber);
//var result = mainQuery.ToList();
result.add(mainQuery.ToList());
}
data = this.Json(result);
data.JsonRequestBehavior = JsonRequestBehavior.AllowGet;
return data;
However, I have a problem in my code; I have to define a main list just before the foreach loop so that I could add results of each query to the that main list. my question is: How can I define this list as you can see at the beginning of my code? Thanks for the help...
How can I define this list as you can see at the beginning of my code?
Make
new {
o.OP_ID,
o.OP_UPD_DATE,
x.EXTERNAL_ID,
o.OP_OS_CODE,
o.OP_START,
o.OP_ST_STATION,
s.START_PRD_ID
}
into a concrete type (say QueryResult, although something a little more specific than that), and then just declare
var result = new List<QueryResult>();
Also, you should consider turning
foreach(long id in PrdIdArr)
and
where s.START_PRD_ID == id
into
where PrdIdArr.Contains(s.Start_PRD_ID)
var result = new List<object>();
foreach(long id in PrdIdArr)
{
....
result.Add(mainQuery.ToList());
}
You could do this:
var result = PrdIdArr.Select(id =>
from o in db.OPERATIONs
join u in db.UNITs on o.OP_UNIT_ID equals u.UNIT_ID into smt
from s in smt
join x in db.XIDs on s.UNIT_ID equals x.UNIT_ID
where o.OP_OT_CODE == OtCode
where x.IDTYP_CD == "BSN"
where s.START_PRD_ID == id
where o.OP_UPD_DATE >= _StartDate
where o.OP_UPD_DATE <= _EndDate
select new
{
o.OP_ID,
o.OP_UPD_DATE,
x.EXTERNAL_ID,
o.OP_OS_CODE,
o.OP_START,
o.OP_ST_STATION,
s.START_PRD_ID
}
.Take(_RowNumber)
.ToList()
).ToList();
I highly recommend performing some Extract Method refactorings, as the code is pretty complex and hard to understand/mange this way.
Just create the anonymous type outside with the same property names and the correct type
var result = Enumerable.Range(0, 0).Select(x => new
{
OP_ID = 1,
OP_UPD_DATE = DateTime.Now,
EXTERNAL_ID = 1,
OP_OS_CODE = 1,
OP_START = DateTIme.Now,
OP_ST_STATION = "",
START_PRD_ID = 1,
}).ToList();
And in your loop call AddRange
result.AddRange(mainQuery.ToList());

How to optimize this LINQ expression?

I have this code:
var query = from deal in db.Deals
where deal.EndDate >= DateTime.UtcNow
select deal;
var priceList = filters.Price.GetPriceRangeList();
foreach(var price in priceList)
{
var startPrice = price.StartPrice;
var endPrice = price.EndPrice;
var priceResult = from deal in query
where (deal.DiscountPrice >= startPrice && deal.DiscountPrice <= endPrice)
select deal;
if(priceResult.Count() != 0)
priceResults = (priceResults == null) ? priceResult : priceResult.Union(priceResults);
}
query = priceResults != null ? query.Intersect(priceResults) : Enumerable.Empty<Deal>().AsQueryable();
My query is slow when priceList has more ten values.
I use Intersect for filters.
How to optimize these queries?
One idea for optimization would be to sort query by StartPrice ascending, that way your inner query can just stop traversal once StartPrice is higher than the DiscountPrice property:
var query = from deal in db.Deals
where deal.EndDate >= DateTime.UtcNow
orderby deal.DiscountPrice ascending
select deal;
..
foreach(..)
{
var startPrice = price.StartPrice;
var endPrice = price.EndPrice;
var queryLocal = query.SkipWhile(deal => deal.DiscountPrice < startPrice);
var priceResult = queryLocal.TakeWhile(deal => deal.DiscountPrice >= startPrice
&& deal.DiscountPrice <= endPrice);
..
}
You have a few issues. The first one is that the query is executed every iteration in your foreach loop. Calling ToList or ToArray will ensure that it is only executed once
Secondly the union is costly. It will iterate priceResult for every iteration of the foreach loop
thirdly your count will also iterate priceResult. Use .Any instead if you wish to know if theres any elements. However I think you can avoid that. If I've read your code correctly I believe the below should have the same result but it does not have the above three issues
var query = (from deal in db.Deals
where deal.EndDate >= DateTime.UtcNow
orderby deal.DiscountPrice ascending
select deal).ToList();
var priceResults = (from price in filters.Price.GetPriceRangeList()
let startPrice = price.StartPrice
let endPrice = price.EndPrice
select query.SkipWhile(d => deal.DiscountPrice < startPrice)
.TakeWhile(d => deal.DiscountPrice <= endPrice)
).SelectMany(x => x);
instead of iterating for each union there's a distinct only once

Linq query: MAX in WHERE

I have a long query that returns
Item {
DateTime entryDate
.....
}
I like to combine the result of this query with another table
Value {
DateTime date,
double value
}
such that if entryDate >= CUTOFF, then take the value on CUTOFF, else take the value on entryDate. In other words, I'd want to achieve:
SELECT Item.*, Value.value WHERE
MIN( Item.entryDate, CUTOFF ) == Value.date
Excuse my syntax, but that's the idea.
EDIT: After some trial and error, I came up with this linq-to-sql query:
from iValue in Values
join iItem in ... (long query)
let targetDate = iItem.EntryDate > CUTOFF ? iItem.EntryDate : CUTOFF
where iValue.Date == targetDate
select new
{
iItem,
targetDate,
iValue
}
Thanks for your help.
yourLongQuery.Where(y => y.Item.entryDate == Value.date || CUTOFF == Value.date)
.Select(x => new {
entrydate = (x.Item.entryDate < CUTOFF ? x.Item.entryDate : CUTOFF),
/*rest of x.Item properties here */ ,
x.Value.date,
x.Value.value
});
Filter the query, Combine the two items into one item and modify the first item
Given that you've returned your data from your Item query and that the Value table is relatively small then this is a nice way to go:
var lookup = values.ToLookup(v => v.date, v => v.value);
var query =
from i in items
let c = i.entryDate < CUTOFF ? i.entryDate : CUTOFF
let v = lookup[c].FirstOrDefault()
select new
{
Item = i,
Value = v,
};
The ToLookup extension is very useful and often overlooked.
such that if entryDate >= CUTOFF, then take the value on CUTOFF, else
take the value on entryDate. In other words, I'd want to achieve:
SELECT Item.*, Value.value WHERE MAX( Item.entryDate, CUTOFF ) ==
Value.date
This is contradictory - if entryDate >= CUTOFF then take the value on CUTOFF imples that you want MIN(Item.entryDate, CUTOFF), not MAX.
Having said that, you just want to select the value.Value that matches each item of your query. Each item should look up the relevant value which matches your MAX (or, I believe, MIN) statement.
query.Select(item =>
{
var matchingValue = Values.Single(v =>
v.date == Min(item.entryDate, CUTOFF));
return new { item, matchingValue.value };
});
This will return an IQueryable of anonymous { Item, double } objects.
If you require this to be a executed as a single SQL statement you'll need to do some refactoring. A good start is to swap matchingValue into a single statement.
query.Select(item => new { item, context.Values.Single(v =>
v.date == Min(item.entryDate, CUTOFF)).value });
I don't have a Visual Studio in front of me to confirm, but I am not sure that the Math.Min function is mapped in LINQ-to-SQL. Let's assume it's not.
query.Select(item => new { item, context.Values.Single(v =>
v.date == (item.entryDate < CUTOFF ? item.entryDate : CUTOFF)).value });
I believe that will resolve to a single query if you execute it with a .ToList() but can't confirm until I have some tools in front of me. Test it with SQL profiler to be sure.

How to make a linq Sum return null if the summed values are all null

I have a LINQ query that looks like this...
var duration = Level3Data.AsQueryable().Sum(d => d.DurationMonths);
If all the d.DurationMonths values are null the Sum returns 0. How can I make the Sum return null if all the d.DurationMonths are null? Or do I need to run a separate query first to eliminate this situation before performing the sum?
Along with the previous suggestion for an extension method - you could use a ternary operator...
var duration = Level3Data.AsQueryable().Any(d => d.DurationMonths.HasValue)
? Level3Data.AsQueryable().Sum(d => d.DurationMonths)
: null;
You can use Aggregate to provide custom aggregation code :
var items = Level3Data.AsQueryable();
var duration = items.Aggregate<D,int?>(null, (s, d) => (s == null) ? d.DurationMonths : s + (d.DurationMonths ?? 0));
(assuming the items in Level3Data are of type D)
var outputIndicatorSum = (from OutputIndicatorTable in objDataBaseContext.Output_Indicators
where OutputIndicatorTable.Output_Id == outputId
select (int?)OutputIndicatorTable.Status).Sum();
int outputIndicatorSumReturn = Convert.ToInt32(outputIndicatorSum);
return outputIndicatorSumReturn;
You can explicitly type cast non-nullable varaible into nullable type.
i.e, select (int?)OutputIndicatorTable.Status).Sum();
Using Sum alone, this is impossible. As you indicated in your question, you will need to check for this situation before you call Sum:
var q = Level3Data.AsQueryable();
var duration = q.All(d => d.DurationMonths == null)
? null
: q.Sum(d => d.DurationMonths);
If you would like the result without two queries try:
var duration = Level3Data.AsQueryable().Sum(d => (double?)d.DurationMonths);
If you want zero instead of null as the result of this query use:
var duration = Level3Data.AsQueryable().Sum(d => (double?)d.DurationMonths) ?? 0;

Resources