How to Group and sum values of two Column in C# Linq - c#

I have this Code. I am unable to add more columns like Date, Name...
var dtt = dt.AsEnumerable()
.GroupBy(p => p.Field<Int64>("ID"))
.Select(p => new
{
ID = p.Key,
Debit = p.Sum(a => a.Field<Decimal>("Debit")),
Credit = p.Sum(a => a.Field<Decimal>("Credit"))
}).ToArray();

You can get name and date one of two ways:
If the Id will always be tied to the same user (i.e. their name), then you can group by Id and Name and return the collection of Date:
var dtt = database.AsEnumerable()
.GroupBy(p => new { p.Field<Int64>("ID"), p.Field<String>("Name")})
.Select(p => new
{
Id = p.Key.ID,
Name = p.Key.Name,
Date = p.Select(a => a.Date),
Debit = p.Sum(a => a.Field<Decimal>("Debit")),
Credit = p.Sum(a => a.Field<Decimal>("Credit"))
}).ToArray();
Or you can use .First() as mentioned in the comments (and still return the collection of Date):
var dtt = database.AsEnumerable()
.GroupBy(p => p.Id)
.Select(p => new
{
Id = p.Id,
Name = p.First().Field<String>("Name"),
Date = p.Select(a => a.Field<DateTime>("Date")),
Debit = p.Sum(a => a.Field<Decimal>("Debit")),
Credit = p.Sum(a => a.Field<Decimal>("Credit"))
}).ToArray();

Related

Optimize linq query by storing value in select

I have problem with linq query. In Select I am getting the same item twice which makes code execution much longer than I can afford. Is there any way to store x.OrderByDescending(z => z.Date).FirstOrDefault() item inside Select query?
Execution time: 180 ms
var groups = dataContext.History
.GroupBy(a => new { a.BankName, a.AccountNo })
.Select(x => new HistoryReportItem
{
AccountNo = x.FirstOrDefault().AccountNo,
BankName = x.FirstOrDefault().BankName,
IsActive = x.FirstOrDefault().IncludeInCheck,
})
.ToList();
Execution time: 1200 ms
var groups = dataContext.History
.GroupBy(a => new { a.BankName, a.AccountNo })
.Select(x => new HistoryReportItem
{
AccountNo = x.FirstOrDefault().AccountNo,
BankName = x.FirstOrDefault().BankName,
IsActive = x.FirstOrDefault().IncludeInCheck,
LastDate = x.OrderByDescending(z => z.Date).FirstOrDefault().Date,
})
.ToList();
Execution time: 2400 ms
var groups = dataContext.History
.GroupBy(a => new { a.BankName, a.AccountNo })
.Select(x => new HistoryReportItem
{
AccountNo = x.FirstOrDefault().AccountNo,
BankName = x.FirstOrDefault().BankName,
IsActive = x.FirstOrDefault().IncludeInCheck,
LastDate = x.OrderByDescending(z => z.Date).FirstOrDefault().Date,
DataItemsCount = x.OrderByDescending(z => z.Date).FirstOrDefault().CountItemsSend
})
.ToList();
You can try doing the select in two steps:
var groups = dataContext.History
.GroupBy(a => new { a.BankName, a.AccountNo })
.Select(x => new
{
first = x.FirstOrDefault();
lastDate = x.OrderByDescending(z => z.Date).FirstOrDefault();
}
.Select(x => new HistoryReportItem
{
AccountNo = x.first.AccountNo,
BankName = x.first.BankName,
IsActive = x.first.IncludeInCheck,
LastDate = x.lastDate.Date,
DataItemsCount = x.lastDate.CountItemsSend
})
.ToList();
If this fails, it might be because the engine can't convert it completely to SQL, and you can try adding an AsEnumerable() between the two Selects.

While fetching all records from the DB, assign to a ViewModel attribute average rating for each record

Basically, I'm fetching all records from a certain table, selecting into a new VM class. I've come up with this code for calculating Average Rating, however, the code produces correct average (grouped by fetched objects' Id). The problem is, these averages/values are in the form of IQueryable whereas I need them to be assigned each to the corresponding record.
return _ctx.LodgingDbSet.Select(x => new LodgingVM
{
LodgingId = x.Id,
LodgingName = x.Name,
LodgingAddress = x.Address,
LodgingEmail = x.Email,
LodgingPhone = x.Phone,
LodgingAverageRating = _ctx.RatingDbSet.GroupBy(
g => g.Reservation.Unit.LodgingId, r => r.Score)
.Select(g => new
{
LodgingId = g.Key,
Score = g.Average()
}).Select(g => g.Score),
LodgingImage = x.Image,
LodgingImageThumb = x.ImageThumb
}).OrderBy(o => o.LodgingName).ToList();
The VM attribute LodgingAverageRating should only contain average value for that particular Lodging. Currently, the code I have for calculating average returns all average values that get calculated.
Try using GroupJoin to Join and group the result and then use Average extension method?
return _ctx.LodgingDbSet.GroupJoin(_ctx.RatingDbSet,
lodging => lodging.Id,
rating => rating.Reservation.Unit.LodgingId,
(l, groupedRating) => new LodgingVM
{
LodgingId = x.Id,
LodgingName = x.Name,
LodgingAddress = x.Address,
LodgingEmail = x.Email,
LodgingPhone = x.Phone,
LodgingAverageRating = groupedRating.Average(x => x.Score),
LodgingImage = x.Image,
LodgingImageThumb = x.ImageThumb
}).OrderBy(o => o.LodgingName).ToList();

How to get pair value from CultureTypes object in C#?

I have created single object of IEnumerable
want to make it dictionary type object to handle key and value.
want to extract Currency Symbol and Name from the Cultures.
IEnumerable<string> currencySymbols = CultureInfo.GetCultures(CultureTypes.SpecificCultures) //Only specific cultures contain region information
.Select(x => (new RegionInfo(x.LCID)).ISOCurrencySymbol )
.Distinct()
.OrderBy(x => x);
foreach(string s in currencySymbols)
{
CurrencyTable tbl = new CurrencyTable();
tbl.Iso = s;
tbl.Name = s;
}
I want like below
IEnumerable<string,string>
How it possible?
CurrencyTable is a class that contains ID | Iso | Name Filed
this one returns all currencySymbols with its first distinct english currency name
var currencySymbols =
CultureInfo.GetCultures(CultureTypes.SpecificCultures) //Only specific cultures contain region information
.Select(x => new RegionInfo(x.LCID))
.GroupBy(x => x.ISOCurrencySymbol)
.Select(x => new CurrencyTable() {
Iso = x.Key,
Name = x.Select(y => y.CurrencyEnglishName).Distinct().FirstOrDefault()
});
and here goes the LINQ-Version:
var symbols = from x in CultureInfo.GetCultures(CultureTypes.SpecificCultures)
let region = new RegionInfo(x.LCID)
group region by region.ISOCurrencySymbol into g
let names = from r in g select r.CurrencyEnglishName
select new CurrencyTable() {
Iso = g.Key,
Name = names.FirstOrDefault()
};
You can't return IEnumerable<string,string>. But you can return IEnumerable<anonymous tyep>.
For example :
var currencyTables = CultureInfo.GetCultures(CultureTypes.SpecificCultures)
.Select(s => new RegionInfo(s.LCID))
.Select(r => new
{
Iso = r.ISOCurrencySymbol,
Name = r.CurrencyEnglishName
}).GroupBy(s => s.Iso)
.OrderBy(r =>r.Key)
.Select(a => new { Iso = a.Key, Name = a.First().Name });
And you can return IEnumerable<CurrencyTable>.
For example:
var currencyTables = CultureInfo.GetCultures(CultureTypes.SpecificCultures)
.Select(s => new RegionInfo(s.LCID))
.Select(r => new
{
Iso = r.ISOCurrencySymbol,
Name = r.CurrencyEnglishName
}).GroupBy(s => s.Iso)
.OrderBy(r =>r.Key)
.Select(a => new CurrencyTable{ Iso = a.Key, Name = a.FirstOrDefault().Name });

Linq - Get Max date from resultset

I need to convert the following SQL query to Linq :-
SELECT CODE,SCODE,MAX(SDATE) AS SDATE FROM SHIFTSCHEDULE
WHERE COMPANY = 'ABC'
GROUP BY CODE,SCODE
ORDER BY MAX(SDATE)
DESC
So far, I have tried this :-
var data = ctx.ShiftSchedule.Where(m =>
m.Company == company && m.EmployeeId == item.EmployeeId
)
.GroupBy(m =>
new
{
m.EmployeeId,
m.ShiftId
})
.Select(m =>
new
{
EmployeeId = m.Key.EmployeeId,
ShiftCode = m.Key.ShiftId,
ShiftDate = m.Max(gg => gg.ShiftDate)
}).ToList();
The results i get are :-
Now what i want is to get record or item in this result set which is MaxDate. In the above image the MaxDate is 1st record.
How to get the MAXDATE from the resultset?
This should work:-
var data = ctx.ShiftSchedule.Where(x => x.Company == company
&& x.EmployeeId == item.EmployeeId)
.GroupBy(x => new { x.CODE, x.SCODE })
.Select(x => new
{
CODE = x.Key.CODE,
SCODE = x.Key.SCODE,
SDATE = x.Max(z => z.SDATE)
})
.OrderByDescending(x => x.SDATE).FirstOrDefault();
You can order the resulting collection and fetch the first object using FirstOrDefault.
If you want just MAXDATE, you can only project that.
Just add .OrderByDescending(x => x.ShiftDate).First(); at the end.
OrderByDescending date and then take .First()
var data = ctx.ShiftSchedule.Where(m =>
m.Company == company && m.EmployeeId == item.EmployeeId
)
.GroupBy(m =>
new
{
m.EmployeeId,
m.ShiftId
})
.Select(m =>
new
{
EmployeeId = m.Key.EmployeeId,
ShiftCode = m.Key.ShiftId,
ShiftDate = m.Max(gg => gg.ShiftDate)
}).ToList().OrderByDescending(x => x.ShiftDate).First();

Remove duplicate rows has the same datetime from List<T>

I have list with 2 parameter's (dynamic)
DateTime OrderDate
decimal TotalPrice
every list may have a same datetime and diffrent price
- DateTime -- Price
- 10/10/10 -- 100
- 11/11/11 -- 111
- 11/11/11 -- 100
- 10/10/10 -- 122
- etc
now i need to combine them. for i see only 1 datetime and 1 price
- DateTime -- Price
- 10/10/10 -- 222
- 11/11/11 -- 211
- etc
here the code
var data = db.CheckOut.Where(x => x.ISOrderComplete == true).OrderBy(c => c.Order.OrderDate).ToArray()
.GroupBy(y => new { OrderDate = y.Order.OrderDate, TotalPrice = y.TotalPrice })
.Select(a => new { OrderDate = a.Key.OrderDate, TotalPrice = a.Key.TotalPrice })
.ToList();
I try to add the function the
var data = db.CheckOut.Where(x => x.ISOrderComplete == true).OrderBy(c => c.Order.OrderDate).ToArray()
.GroupBy(y => new { OrderDate = y.Order.OrderDate, TotalPrice = y.TotalPrice })
.Select(a => new { OrderDate = a.Key.OrderDate, TotalPrice = a.Sum(b => b.TotalPrice) })
.ToList();
What i have to do?
i dont need this sum in db. i need this sum to display statistic about incoms to company in charts so i need to sum each data for how much getting .
var data = db.CheckOut.Where(x => x.ISOrderComplete == true)
.GroupBy(y => new { OrderDate = y.Order.OrderDate})
.Select(a => new { OrderDate = a.Key.OrderDate, TotalPrice = a.Sum(b => b.TotalPrice)})
.OrderBy(c => c.Order.OrderDate)
.ToList();
Following deramko approach, the only missing thing is that you shouldn't group by OrderDate, but instead, OrderDate.Date, because the time can be different.
Try something like this:
var data = db.CheckOut.Where(x => x.IsCheckoutComplete)
.GroupBy(x => new { OrderDate = x.Order.OrderDate.Date})
.Select(a => new { OrderDate = a.Key.OrderDate, TotalPrice = a.Sum(b => b.Order.TotalPrice)})
.OrderBy(c => c.OrderDate)
.ToList();
You can check it on https://dotnetfiddle.net/3mrZkf
becuse in Linq we cant groupby orderdate.date so i split it. then we can order by the date.
public JsonResult TotalIncomeJson()
{
var tempD = db.CheckOut.Where(x => x.ISOrderComplete).ToList();
var data = tempD.GroupBy(x => x.Order.OrderDate.Date).Select(y => new { OrderDate = y.Key, TotalPrice = y.Sum(a => a.TotalPrice) })
.OrderBy(b=>b.OrderDate.Year).ToList();
return Json(data, JsonRequestBehavior.AllowGet);
}

Categories