I have this piece of code where highAmtCtrList is a list of Outstanding contracts that have to be updated and comCtrList is a list of Dilution contracts from which I update highAmtCtrList.
So, for each conctract in highAmtCtrList, if I find a matching contract in comCtrList, I update it with the amount returned from comCtrList.
The code works, it's just that I would like to change it to linq.
Any ideas.
tks in advance.
Rui Martins
foreach (Outstanding outCtr in highAmtCtrList)
{
Dilution dilCtr =
comCtrList.FirstOrDefault(dil => dil.Contract == outCtr.Contract);
if (dilCtr != null) outCtr.Amount += dilCtr.Amount;
}
Your code looks fine. You can write all this in one line, but IMO it's a less maintainable code:
outCtr.Join(comCtrList,
o => o.Contract,
i => i.Contract,
(o, i) => o.Amount += i.Amount);
EDIT: to sum only first matches:
outCtr.ForEach(o => o.Amount += comCtrList
.Where(i => i.Contract == o.Contract)
.Select(i => i.Amount)
.FirstOrDefault());
How about this?
foreach (Outstanding o in highAmtCtrList)
{
o.Amount += comCtrList.Where(d => d.Contract == o.Contract)
.Select(d => d.Amount)
.FirstOrDefault();
}
Here's another alternative:
foreach (Outstanding o in highAmtCtrList)
{
o.Amount += comCtrList.Where(d => d.Contract == o.Contract)
.Take(1)
.Sum(d => d.Amount);
}
Related
The following query works, but I want to get the same result without using grp.Sum(). Can we do it?
from item in (await VehicleReplaceCostDataAsync())
group item by (item.type, item.size, item.ADA, item.eseq) into grp
orderby (grp.Key.eseq, grp.Key.size, grp.Key.ADA)
select new VehicleReplacementCost
{
type = grp.Key.type,
size = grp.Key.size,
ADA = grp.Key.ADA,
count = grp.Sum(x => x.count),
cost = grp.Sum(x => x.cost),
Fcount = grp.Sum(x => x.Fcount),
Fcost = grp.Sum(x => x.Fcost),
eseq = grp.Key.eseq,
}).ToList();
Perhaps by using .Aggregate()? [docs]
count = grp.Aggregate(0, (a, b) => a + b.count)
Thanks for the answer from Astrid. It looks like a good one, but I didn't test it. My colleague gave this solution instead by using yield:
var groups = costs
.GroupBy(type => (type.SystemId, type.Type, type.Size, type.ADA, type.Eseq))
.OrderBy(group => (group.Key.SystemId, group.Key.Eseq, group.Key.Size, group.Key.ADA));
foreach (var group in groups)
{
var result = new ProgramGuideVehicleCostRow
{
SystemId = group.Key.SystemId,
Type = group.Key.Type,
Size = group.Key.Size,
ADA = group.Key.ADA,
};
foreach (var row in group)
{
result.Cost += row.Cost;
result.Fcost += row.Fcost;
result.Count += row.Count;
result.Fcount += row.Fcount;
}
yield return result;
}
in the following code i've commented on the line that SLOWS my page right down. I did some speed test to reveal the CONTAINS LINQ expression is the problem.
Does anyone know how to change this one line to be more efficient using something else instead. I'm also curious as to why its so slow.
Any ideas (thanks in advance):
var allWaste = _securityRepository.FindAllWaste(userId, SystemType.W);
var allWasteIndicatorItems = _securityRepository.FindAllWasteIndicatorItems();
// First get all WASTE RECORDS
var searchResults = (from s in allWaste
join x in allWasteIndicatorItems on s.WasteId equals x.WasteId
where (s.Description.Contains(searchText)
&& s.Site.SiteDescription.EndsWith(searchTextSite)
&& (s.CollectedDate >= startDate && s.CollectedDate <= endDate))
&& x.EWC.EndsWith(searchTextEWC)
select s).Distinct();
var results = searchResults.AsEnumerable();
if (hazardous != "-1")
{
// User has requested to filter on Hazardous or Non Hazardous only rather than Show All
var HazardousBoolFiltered = (from we in _db.WasteIndicatorItems
.Join(_db.WasteIndicators, wii => wii.WasteIndicatorId, wi => wi.WasteIndicatorId, (wii, wi) => new { wasteid = wii.WasteId, wasteindicatorid = wii.WasteIndicatorId, hazardtypeid = wi.HazardTypeId })
.Join(_db.HazardTypes, w => w.hazardtypeid, h => h.HazardTypeId, (w, h) => new { wasteid = w.wasteid, hazardous = h.Hazardous })
.GroupBy(g => new { g.wasteid, g.hazardous })
.Where(g => g.Key.hazardous == true && g.Count() >= 1)
select we).AsEnumerable(); // THIS IS FAST
// Now join the 2 object to eliminate all the keys that do not apply
if (bHazardous)
results = (from r in results join x in HazardousBoolFiltered on r.WasteId equals x.Key.wasteid select r).AsEnumerable(); //This is FAST
else
results = (from r in results.Where(x => !HazardousBoolFiltered
.Select(y => y.Key.wasteid).Contains(x.WasteId)) select r).AsEnumerable(); // This is DOG SLOW 10-15 seconds !--- THIS IS SLOWING EXECUTION by 10 times --!
}
return results.AsQueryable();
I suggest using a logging / tracing framework like smart inspect or log4net combined with a debug text writer.
http://www.codesprouts.com/post/View-LINQ-To-SQL-Statements-Using-A-Debug-TextWriter.aspx
another possibility is to use the sql server profiler and see what sql linq2sql produces.
also a very nice way is to use the mvc mini profiler in combination with the Profiled DB Connection and the SqlFormatters.SqlServerFormatter.
Try Any (MSDN)
Try this:
results = (from r in results
.Where(x => !HazardousBoolFiltered
.Any(y => y.Key.wasteid == r.WasteId)))
.AsEnumerable()
Or Count:
results = (from r in results
.Where(x => HazardousBoolFiltered
.Count(y => y.Key.wasteid == r.WasteId) == 0))
.AsEnumerable()
In my code below, is there any way I can use the results in the object 'WasteRecordsExcluded' to join with searchResults, essentially excluding the WasteId's I don't want.
If I debug to the last line I get the error :
base {System.SystemException} = {"The query contains references to items defined on a different data context."}
Or if joining is impossible then i could change bHazardous from TRUE to FALSE and FALSE to TRUE and do some kind of 'NOT IN' comparison.
Going bananas with this one, anyone help? Kind Regards :
var allWaste = _securityRepository.FindAllWaste(userId, SystemType.W);
var allWasteIndicatorItems = _securityRepository.FindAllWasteIndicatorItems();
// First get all WASTE RECORDS
var searchResults = (from s in allWaste
join x in allWasteIndicatorItems on s.WasteId equals x.WasteId
where (s.Description.Contains(searchText)
&& s.Site.SiteDescription.EndsWith(searchTextSite)
&& (s.CollectedDate >= startDate && s.CollectedDate <= endDate))
&& x.EWC.EndsWith(searchTextEWC)
select s).Distinct();
var results = searchResults;
if (hazardous != "-1")
{
// User has requested to filter on Hazardous or Non Hazardous only rather than Show All
var WasteRecordsExcluded = (from we in _db.WasteIndicatorItems
.Join(_db.WasteIndicators, wii => wii.WasteIndicatorId, wi => wi.WasteIndicatorId, (wii, wi) => new { wasteid = wii.WasteId, wasteindicatorid = wii.WasteIndicatorId, hazardtypeid = wi.HazardTypeId })
.Join(_db.HazardTypes, w => w.hazardtypeid, h => h.HazardTypeId, (w, h) => new { wasteid = w.wasteid, hazardous = h.Hazardous })
.GroupBy(g => new { g.wasteid, g.hazardous })
.Where(g => g.Key.hazardous == bHazardous && g.Count() >= 1)
select we);
// Now join the 2 object to eliminate all the keys that do not apply
results = results.Where(n => WasteRecordsExcluded.All(t2 => n.WasteId == t2.Key.wasteid));
}
return results;
Maybe something like this:
.....
var results = searchResults.ToList();
.....
.....
.Where(g => g.Key.hazardous == bHazardous && g.Count() >= 1)
select we).ToList();
.....
I currently have a LINQ query:
public List<EventSchool> GetEventSchools(int eventID)
{
var eventSchools = db.EventSchools
.Include("Organisation")
.Where(e => e.EventID == eventID)
.ToList();
foreach (var ev in eventSchools)
{
if (db.EventSchoolKeyStages.Where(e => e.EventSchoolID == ev.EventSchoolID).Count() > 0)
{
int ks = db.EventSchoolKeyStages
.Where(e => ev.EventSchoolID == ev.EventSchoolID)
.Sum(e => e.Males + e.Females);
ev.StudentNumbers = ks;
}
}
return eventSchools;
}
When I inspect EventSchools, the student numbers for ALL items in the list shows as the first total.
For example, if I have 3 items in the list:
Item 1 - Males = 10, Females = 10
Item 2 - Males = 1, Females = 2
Item 3 - Males = 200, Females = 500
ALL items have a StudentNumbers of 20, rather than:
Item 1 - 20
Item 2 - 3
Item 3 - 700
Not sure what I'm doing wrong?
You have a typo here:
.Where(e => ev.EventSchoolID == ev.EventSchoolID)
This lambda will always be true. I suspect you meant
.Where(e => e.EventSchoolID == ev.EventSchoolID)
^^^
which is different in the indicated place.
You have an error in your query:
.Where(e => ev.EventSchoolID == ev.EventSchoolID)
Should be:
.Where(e => e.EventSchoolID == ev.EventSchoolID)
I'm getting the following error:
The type of one of the expressions in the join clause is incorrect. Type inference failed in the call to 'Join'.
when using the code below
var ccrCodes = (from c in db.CCRCodes
join i in items on
new { c.baan_cat_fam_code, c.baan_cat_code } equals
new { i.baan_cat_family_code, i.baan_cat_code }
where i => i.contact_dt.Value.Year == date.Year && i.contact_dt.Value.Month == date.Month
select c).Distinct().OrderBy(c => c.code_desc);
What I'm trying to do in LINQ is create a multi-condition join and am running into problems. Any ideas?
Thanks,
Try giving names to the properties in your anonymous objects:
var ccrCodes = (from c in db.CCRCodes
join i in items on
new { FamCode = c.baan_cat_fam_code, CatCode = c.baan_cat_code } equals
new { FamCode = i.baan_cat_family_code, CatCode = i.baan_cat_code }
where i => i.contact_dt.Value.Year == date.Year && i.contact_dt.Value.Month == date.Month
select c).Distinct().OrderBy(c => c.code_desc);
EDIT: Alright, I have to confess, I am no expert on query syntax, but you want to filter the 'items' list before doing the join, like the following fluent version of your query:
db.CCRCodes
.Join(
items.Where(i => i.contact_dt.Value.Year == date.Year && i.contact_dt.Value.Month == date.Month),
x => new { FamCode = x.baan_cat_fam_code, CatCode = x.baan_cat_code },
x => new { FamCode = x.baan_cat_family_code, CatCode = x.baan_cat_code },
(o,i) => o
).Distinct().OrderBy(c => c.code_desc)
ANOTHER EDIT: Per Ahmad's suggestion:
var ccrCodes = (from c in db.CCRCodes
join i in items.Where(x => x.contact_dt.Value.Year == date.Year && x.contact_dt.Value.Month == date.Month) on
new { FamCode = c.baan_cat_fam_code, CatCode = c.baan_cat_code } equals
new { FamCode = i.baan_cat_family_code, CatCode = i.baan_cat_code }
select c).Distinct().OrderBy(c => c.code_desc);
YET ANOTHER EDIT: Per another Ahmad suggestion:
var ccrCodes = (from c in db.CCRCodes
from i in items
where i.contact_dt.Value.Year == date.Year && i.contact_dt.Value.Month == date.Month
&& c.baan_cat_fam_code == i.baan_cat_family_code && c.baan_cat_code == i.baan_cat_code
select c).Distinct().OrderBy(c => c.code_desc);