EF core Get Count and sum in one call - c#

Using Entity Framework core, can I get the total sum of the column and row count in one call?
I have the following code, but I think there is a better way to do this.
TotalCostResponse result = new TotalCostResponse
{
TotalCost = await dbContext.Transaction
.Where(x => x.UserName == request.UserName
&& x.Date >= request.StartDate
&& x.Date <= request.EndDate)
.SumAsync(x => x.Amount),
TotalNumber = await dbContext.Transaction
.Where(x => x.UserName == request.UserName
&& x.Date = request.StartDate
&& x.Date <= request.EndDate)
.CountAsync()
};
So instead of calling dbContext two times, I need to make it in one call.

var result = await dbContext.Transaction
.Where(x => x.UserName == request.UserName
&& x.Date >= request.StartDate
&& x.Date <= request.EndDate)
.GroupBy(x => 1)
.Select(group => new TotalCostResponse
{
TotalCost = group.Sum(x => x.Amount),
TotalNumber = group.Count()
})
.FirstOrDefaultAsync();

Here is an example with one query, there are certainly other ways that you can find.
// In the select get only what you need, in your case only the amount
var transactions =
await this.dbContext.Transaction
.Where(x => x.UserName == request.UserName
&& x.Date >= request.StartDate
&& x.Date <= request.EndDate)
.Select(y => new
{
Amount = y.Amount,
}).ToListAsync();
// Calculating the data
var result = new TotalCostResponse
{
TotalCost = transactions.Sum(x => x),
TotalNumber = transactions.Count(),
}

Related

How to use Exist sql function in Linq

var _query = _dbContext.CashVoucherDetails
.Where(x => x.CreationDate.Date >= From.Date && x.CreationDate.Date <= To.Date && (x.Type == Common.TransactionType.CPV || x.Type == Common.TransactionType.BPV) && x.CompanyCode == BranchCode && x.DebitAmount > 0)
.GroupBy(v => new { v.AccountCode})
.Select(g => new
{
AccountCode = g.Key.AccountCode,
});
var balances = _dbContext.CashVoucherDetails
.Where(x => x.CreationDate.Date <= To.Date && x.CompanyCode == BranchCode)
//.Exist(_query.Account) (I want only account which exist in upper query)
.GroupBy(v => new { v.AccountCode})
.Select(g => new
{
AccountCode = g.Key.AccountCode,
Balance = g.Sum(x => x.DebitAmount - x.CreditAmount),
});
I want to use something like EXIST here in first query I have some specific accounts and in 2nd query I want to calculate balances of those accounts.
Can you please tell how I can use Exist function in LINQ.
Thank you.
I want this query to be implemented in LINQ:
SELECT `c`.`AccountCode`, `c`.`CompanyCode` AS `LocationCode`, COALESCE(SUM(`c`.`DebitAmount` - `c`.`CreditAmount`), 0) AS `Balance`
FROM `CashVoucherDetails` AS `c`
WHERE (CONVERT(`c`.`CreationDate`, date) <= '2022-12-20') AND (`c`.`CompanyCode` = '002') and `c`.`AccountCode` IN
(
SELECT `c`.`AccountCode`
FROM `CashVoucherDetails` AS `c`
WHERE ((((CONVERT(`c`.`CreationDate`, date) >= '2022-12-20') AND (CONVERT(`c`.`CreationDate`, date) <= '2022-12-20')) AND `c`.`Type` IN ('CPV', 'BPV')) AND (`c`.`CompanyCode` = '002')) AND (`c`.`DebitAmount` > 0)
GROUP BY `c`.`AccountCode`
)
GROUP BY `c`.`AccountCode`, `c`.`CompanyCode`;
you can use Contains or Any.
_dbContext.CashVoucherDetails
.Where(x => x.CreationDate.Date <= To.Date && x.CompanyCode == BranchCode)
.Where(x => _query.Select(q => q.AccountCode).Contains(x.AccountCode))
Or
.Where(x => _query.Any(q => q.AccountCode == x.AccountCode))
Maybe something like that
var balances = _dbContext.CashVoucherDetails
.Where(x => x.CreationDate.Date <= To.Date && x.CompanyCode == BranchCode && _query.Any(q => q.AccountCode == x.AccountCode))
.GroupBy(v => new { v.AccountCode})
.Select(g => new
{
AccountCode = g.Key.AccountCode,
Balance = g.Sum(x => x.DebitAmount - x.CreditAmount),
});

How to improve this C# Linq Concat Example?

The following C# Linq example displays the correct records in a serverSide datatable. However, when I add the following line: data = data.Concat(unconfirmed);, it increases the page/datatable load time from ~500 ms to ~2 seconds when year equals the current year. Searching by the current year displays the most amount of records, but they are only ~90. Searching by a previous year displays ~10 records at most and it only takes ~500 ms for the page/datatable to load:
var data = _db.ResidencyConfirmations.AsQueryable();
var year = Request.Form.GetValues("columns[11][search][value]")[0];
var showConfirmed = Request.Form.GetValues("columns[12][search][value]")[0];
int.TryParse(year, out var resultYear);
data = data.Where(rc => rc.Application.ApplicationType.Label == "Home Rehab");
var allNotesReleased = data.Where(rc => rc.Application.ApplicationActivityPhas
.Where(aap => aap.ActivityPhas.WorkFlowStep == 6)
.Select(aap => aap.ActivityPhas.ActivityPhase)
.FirstOrDefault() == "All Notes Released" &&
rc.Application.ApplicationActivityPhas
.Where(aap => aap.ActivityPhas.WorkFlowStep == 6)
.Select(aap => aap.ActivityPhaseDate)
.FirstOrDefault().Year >= resultYear);
var complete = data.Where(rc => rc.Application.ApplicationActivityPhas
.Where(aap => aap.ActivityPhas.WorkFlowStep == rc.Application.ApplicationActivityPhas
.Max(x => x.ActivityPhas.WorkFlowStep))
.Select(aap => aap.ActivityPhas.ActivityPhase)
.FirstOrDefault() == "Complete" &&
rc.Application.ApplicationActivityPhas
.Where(aap => aap.ActivityPhas.WorkFlowStep == 5)
.Select(aap => aap.ActivityPhaseDate)
.FirstOrDefault().Year < resultYear);
var unconfirmed = complete.Where(rc => !rc.Application.ResidencyConfirmations
.Any(x => x.ResidencyConfirmationDate.Year == resultYear))
.GroupBy(rc => rc.Application.AppNumber)
.Select(rc => rc.OrderByDescending(x => x.ResidencyConfirmationDate)
.FirstOrDefault());
data = allNotesReleased.Concat(complete)
.Where(rc => rc.ResidencyConfirmationDate.Year == resultYear);
if (showConfirmed == "false")
data = data.Where(rc => !rc.Deed || !rc.Utility || !rc.VitalRecords);
data = data.Concat(unconfirmed);
Not sure how it compiles, written in text editor, but query should be faster. Note that instead of using .Year introduced range variables, it will speedup query if you have indexes on date.
var year = Request.Form.GetValues("columns[11][search][value]")[0];
var showConfirmed = Request.Form.GetValues("columns[12][search][value]")[0];
int.TryParse(year, out var resultYear);
var startOfTheYear = new DateTime(resultYear, 1, 1);
var nextYear = startOfTheYear.AddYears(1);
var data = _db.ResidencyConfirmations.AsQueryable();
data = data.Where(rc => rc.Application.ApplicationType.Label == "Home Rehab");
var allNotesReleased =
from rc in data
from aap in rc.Application.ApplicationActivityPhas
.Where(aap => aap.ActivityPhas.WorkFlowStep == 6)
.Take(1)
where
aap.ActivityPhas.ActivityPhase == "All Notes Released" &&
app.ActivityPhaseDate >= startOfTheYear &&
rc.ResidencyConfirmationDate >= startOfTheYear && rc.ResidencyConfirmationDate < nextYear
select rc;
var complete =
from rc in data
from aap in rc.Application.ApplicationActivityPhas
.OrderByDescending(aap => aap.WorkFlowStep)
.Take(1)
from aap2 in rc.Application.ApplicationActivityPhas
.Where(aap2 => aap2.ActivityPhas.WorkFlowStep == 5)
.Take(1)
where
aap.ActivityPhas.ActivityPhase == "Complete" &&
app2.ActivityPhaseDate < startOfTheYear &&
rc.ResidencyConfirmationDate >= startOfTheYear && rc.ResidencyConfirmationDate < nextYear
select rc;
var unconfirmed = complete
.Where(rc => !rc.Application.ResidencyConfirmations
.Any(x => x.ResidencyConfirmationDate >= startOfTheYear && x.ResidencyConfirmationDate < nextYear)
)
.GroupBy(rc => rc.Application.AppNumber)
.Select(rc => rc
.OrderByDescending(x => x.ResidencyConfirmationDate)
.First()
);
if (showConfirmed == "false")
data = data.Where(rc => !rc.Deed || !rc.Utility || !rc.VitalRecords);
data = data.Concat(unconfirmed);
To improve performance and to display the correct records, I made the following changes/additions:
if (resultYear == DateTime.Now.Year)
data = data.Where(rc => rc.Application.ApplicationType.Label == "Home Rehab")
.GroupBy(rc => rc.Application.AppNumber)
.Select(rc => rc.OrderByDescending(x => x.ResidencyConfirmationDate)
.FirstOrDefault());
else
data = data.Where(rc => rc.Application.ApplicationType.Label == "Home Rehab");
IQueryable<ResidencyConfirmation> unconfirmed = null;
if (resultYear == DateTime.Now.Year)
unconfirmed = complete.Where(rc => !rc.Application.ResidencyConfirmations
.Any(x => x.ResidencyConfirmationDate.Year == resultYear));
else
unconfirmed = complete.Where(rc => !rc.Application.ResidencyConfirmations
.Any(x => x.ResidencyConfirmationDate.Year == resultYear))
.GroupBy(rc => rc.Application.AppNumber)
.Select(rc => rc.OrderByDescending(x => x.ResidencyConfirmationDate)
.FirstOrDefault());
It now takes right under 1 second for the page/datatable to load.

optimize query with lambra expression in entity framework

I have the following query, often have excution timeout errors, have any ideas for optimization.
Thank you!
queryResult = db.Products
.Where(x => !x.product_is_deleted)
.Where(x => x.product_name.Contains(keyword) || x.product_barcode.Contains(keyword) || x.ProductType.pro_type_name.Contains(keyword) || x.ProductType.pro_type_name.Contains(keyword))
.Select(x => new ProductView
{
product_id = x.product_id,
product_barcode = x.product_barcode,
product_name = x.product_name,
product_unit = x.product_unit,
product_size = x.product_size,
product_weight = x.product_weight,
product_type_id = x.product_type_id,
product_inventory = shelf == 0 ? (x.ImportProductDetails.Where(y => y.imp_pro_detail_product_id == x.product_id && y.ImportProduct.import_pro_warehouse_id == warehouse_id ).Select(y => y.imp_pro_detail_inventory).DefaultIfEmpty(0).Sum()) : (x.ImportProductDetails.Where(y => y.imp_pro_detail_product_id == x.product_id && y.ImportProduct.import_pro_warehouse_id == warehouse_id && y.imp_pro_detail_shelf_id == shelf).Select(y => y.imp_pro_detail_inventory).DefaultIfEmpty(0).Sum()),
product_opening_stock = x.product_opening_stock,
product_type_name = x.ProductType.pro_type_name,
product_price = x.ProductPrices.Where(y => !y.proprice_is_deleted).Where(y => y.proprice_applied_datetime <= DateTime.Now).OrderByDescending(y => y.proprice_applied_datetime).Select(y => y.proprice_price).FirstOrDefault(),
product_discount_type = x.ProductDiscounts.Where(y => !y.pro_discount_is_deleted && y.pro_discount_start_datetime <= datetimeNow && y.pro_discount_end_datetime >= datetimeNow).OrderByDescending(y => y.pro_discount_id).Select(y => y.pro_discount_type).FirstOrDefault(),
product_discount_value = x.ProductDiscounts.Where(y => !y.pro_discount_is_deleted && y.pro_discount_start_datetime <= datetimeNow && y.pro_discount_end_datetime >= datetimeNow).OrderByDescending(y => y.pro_discount_id).Select(y => y.pro_discount_value).FirstOrDefault()
//product_norm_name = x.ProductionNorms.Where(y => y.pro_norm_name == x.product_id && y.pro_norm_is_applied == true).Select(y => y.pro_norm_id).FirstOrDefault()
});

How can I write this with where clause where CreatedDate is in between Date1var & Date2var?

How can I write this with where clause where CreatedDate is in between Date1var & Date2var?
return _context.Logs.Where(x => x.ApplicationID == applicationId)
.OrderByDescending(x => x.ID)
.Take(count)
.Select(record => new LoggingLogic.entities.Log
{
DataL = record.Data,
LogMessage = record.Message,
CreatedDate = record.CreateDate,
ApplicationName = record.Application.Name,
Environment = record.Application.Environment.EnvironmentName,
ID = record.ID
});
Change your Where() to Where(x => x.ApplicationID = applicationId && x.CreatedDate >= Date1var && x.CreatedDate <= Date2var)
I'm assuming that you want the range to be inclusive.
try this
return _context.Logs.Where(x => x.ApplicationID == applicationId && x.CreatedDate >= Date1Var && x.CreatedDate <= Date2Var)
.OrderByDescending(x => x.ID)
.Take(count)
.Select(record => new LoggingLogic.entities.Log
{
DataL = record.Data,
LogMessage = record.Message,
CreatedDate = record.CreateDate,
ApplicationName = record.Application.Name,
Environment = record.Application.Environment.EnvironmentName,
ID = record.ID
});

Mixing two linq statement into one?

I have 2 linq statements, both of them are fully working. I am wondering if it is possible to mix them into one and get proper list after one linq.
var result = list3.Where(Srodek => list4.Any(x => x == Srodek.Srodek.category1) &&
(Srodek.Srodek.Source.Device == _text || Srodek.Srodek.ID.Device == _text))
.ToList();
var list666 = list3.Select(obj => new { obj, dt = DateTime.ParseExact(obj.LeftColumn, dateFormat, CultureInfo.InvariantCulture) })
.Where(x => x.dt >= czas11 && x.dt <= czas22)
.Select(x => x.obj).ToList();
LINQ methods return IEnumerable<T>, and can operate on IEnumerable<T>.
You can write
sequence.Where(...).Select(...)
One list:
var result = list3.Where(obj => {
var dt = DateTime.ParseExact(obj.LeftColumn, dateFormat, CultureInfo.InvariantCulture);
return (list4.Any(x => x == obj.Srodek.category1) &&
(obj.Srodek.Source.Device == _text || obj.Srodek.ID.Device == _text)) ||
(dt >= czas11 && dt <= czas22);})
.ToList();
Why you cant just mix them? list.where(.........).select(.......).toList();
var result = list3.Where(Srodek => list4.Any(x => x == Srodek.Srodek.category1) &&
(Srodek.Srodek.Source.Device == _text || Srodek.Srodek.ID.Device== _text))
.Select(obj => new { obj, dt = DateTime.ParseExact(obj.LeftColumn, dateFormat, CultureInfo.InvariantCulture) })
.Where(x => x.dt >= czas11 && x.dt <= czas22)
.Select(x => x.obj)
.ToList();
You can join both linq queries using Union.
list3.Where(Srodek => list4.Any(x => x == Srodek.Srodek.category1) &&
(Srodek.Srodek.Source.Device == _text || Srodek.Srodek.ID.Device == _text))
.Union(list3.Select(obj => new { obj, dt = DateTime.ParseExact(obj.LeftColumn, dateFormat, CultureInfo.InvariantCulture) })
.Where(x => x.dt >= czas11 && x.dt <= czas22)
.Select(x => x.obj));

Categories