Can my two linq lines of code be combined? - c#

I'm not sure how to do this since I'm only familiar with the basic form or Linq.
Here are my two sets of code:
var qry = from x in CustomersChecks.CustomersChecksList
where x.RoutingNumber == routingnumber &&
x.BankAccountNumber == bankAccountNumber &&
x.Branch > 0 &&
x.AccountNumber > 0
orderby x.Name
select x;
var qry2 = qry.GroupBy(x => new { x.Branch, x.AccountNumber}).Select(x => x.First()).ToList();
Ultimately, I want to get my first query in order of Branch + Account Number distinctly.
Can they be combined or is what I have the only way to do this?

The quick and dirty solution is just to add the GroupBy chain to the end of the first query.
var qry = (from x in CustomersChecks.CustomersChecksList
where x.RoutingNumber == routingnumber &&
x.BankAccountNumber == bankAccountNumber &&
x.Branch > 0 &&
x.AccountNumber > 0
orderby x.Name
select x).GroupBy(x => new { x.Branch, x.AccountNumber})
.Select(x => x.First())
.ToList();
Or do the following by incorrupating the group by into the exist query syntax
var qry = (from x in CustomersChecks.CustomersChecksList
where x.RoutingNumber == routingnumber &&
x.BankAccountNumber == bankAccountNumber &&
x.Branch > 0 &&
x.AccountNumber > 0
orderby x.Name
group x by new { x.Branch, x.AccountNumber} into grp
select grp.First()).ToList();

var qry = CustomersChecks.CustomersChecksList.Where(x =>
x.RoutingNumber == routingnumber &&
x.BankAccountNumber == bankAccountNumber &&
x.Branch > 0 &&
x.AccountNumber > 0).OrderBy(x => x.Name)
.GroupBy(x => new { x.Branch, x.AccountNumber})
.Select(x => x.First())
.ToList();

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),
});

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()
});

C# Linq multiple queries in a single one

I'm new in Linq and I'm trying to optimize some queries and I don't have any idea if it is possible for this queries:
var cSRez = (from l in MyTable
where l.Name == "dcc" && l.Service == "Main"
orderby l.Time descending
select l.Value).FirstOrDefault();
var cDRez = (from l in MyTable
where l.Name == "dcc" && l.Service == "DB"
orderby l.Time descending
select l.Value).FirstOrDefault();
var dSRez = (from l in MyTable
where l.Name == "ddc" && l.Service == "Main"
orderby l.Time descending
select (long?)l.Value).FirstOrDefault();
var dDRez = (from l in MyTable
where l.Name == "ddc" && l.Service == "DB"
orderby l.Time descending
select (long?)l.Value).FirstOrDefault();
var mSRez = (from l in MyTable
where l.Name == "mc" && l.Service == "Main"
orderby l.Time descending
select l.Value).FirstOrDefault();
var mDRez = (from l in MyTable
where l.Name == "mc" && l.Service == "DB"
orderby l.Time descending
select l.Value).FirstOrDefault();
to become a single one.
I was thinking about row_number() over(partition by... (SQL) but I don't think this is the best idea for doing this.
It is possible to collapse this six separate queries into a single one?
You'd need to group on the Name and Service and then filter on the specific pairs you want then select the Name and Service and the Value from the First match. Note that any pairs that do not exist will not be represented in the results and you'd have to handle that when you pull the values out.
var results = (from l in MyTable
group l by new {l.Name, l.Service} into grp
where (grp.Key.Name == "dcc" && grp.Key.Service == "Main")
|| (grp.Key.Name == "dcc" && grp.Key.Service == "DB")
|| ....
select new
{
grp.Key,
Value = grp.OrderByDescending(x => x.Time).Select(x => x.Value).First()
}).ToDictionary(x => x.Key, x => x.Value);
Then to pull out the results
results.TryGetValue(new { Name = "dcc", Service = "Main" }, out var cSRez);
I am not sure how EF would translate this query to SQL, but I would try this approach:
var rawData = MyTable
.Where(l => (l.Name=="dcc" || l.Name=="ddc" || l.Name=="mc") && (l.Service=="Main" || l.Service=="Db"))
.GroupBy(l => new { l.Name, l.Service })
.Select(g => g.OrderByDescending(l => l.Time).First())
.ToList();
This should yield up to six rows of interest to your program. Now you can retrieve each row by specifying the specific combination of Name and Service:
var cSRez = rawData.FirstOrDefault(l => l.Name == "dcc" && l.Service == "Main");
var cDRez = rawData.FirstOrDefault(l => l.Name == "dcc" && l.Service == "DB");
var dSRez = rawData.FirstOrDefault(l => l.Name == "ddc" && l.Service == "Main");
var dDRez = rawData.FirstOrDefault(l => l.Name == "ddc" && l.Service == "DB");
var mSRez = rawData.FirstOrDefault(l => l.Name == "mc" && l.Service == "Main");
var mDRez = rawData.FirstOrDefault(l => l.Name == "mc" && l.Service == "DB");
Note that the six queries on rawData are performed in memory on a list of fixed size of up to six items, so they are not costing you additional round-trips to RDBMS.
I am not sure if this will execute faster as a single query or not, as the query is somewhat complex, so I think it may depend on server side query time versus query setup and data transmission time.
You can convert into a single query that gathers all the answers at once, and then break that answer up for each variable.
This first answer takes the result and converts into a double nested Dictionary for the values and then pulls the variables out of the Dictionary:
var ansd = (from l in MyTable
where new[] { "dcc", "ddc", "mc" }.Contains(l.Name) && new[] { "Main", "DB" }.Contains(l.Service)
group l by new { l.Name, l.Service } into ag
select new {
ag.Key.Name,
ag.Key.Service,
Value = ag.OrderByDescending(l => l.Time).First().Value
})
.GroupBy(nsv => nsv.Name)
.ToDictionary(nsvg => nsvg.Key, nsvg => nsvg.ToDictionary(nsv => nsv.Service, arv => arv.Value));
long? cSRez = null, cDRez = null, dSRez = null, dDRez = null, mSRez = null, mDRez = null;
if (ansd.TryGetValue("dcc", out var td)) td.TryGetValue("Main", out cSRez);
if (ansd.TryGetValue("dcc", out td)) td.TryGetValue("DB", out cDRez);
if (ansd.TryGetValue("ddc", out td)) td.TryGetValue("Main", out dSRez);
if (ansd.TryGetValue("ddc", out td)) td.TryGetValue("DB", out dDRez);
if (ansd.TryGetValue("mc", out td)) td.TryGetValue("Main", out mSRez);
if (ansd.TryGetValue("mc", out td)) td.TryGetValue("DB", out mDRez);
Given that there are only six answers, creating Dictionarys for them may be overkill. Instead, you can just (sequentially) find the matching answers:
var ansl = (from l in MyTable
where new[] { "dcc", "ddc", "mc" }.Contains(l.Name) && new[] { "Main", "DB" }.Contains(l.Service)
group l by new { l.Name, l.Service } into ag
select new {
ag.Key.Name,
ag.Key.Service,
Value = ag.OrderByDescending(l => l.Time).First().Value
})
.ToList();
var cSRez = ansl.FirstOrDefault(ansv => ansv.Name == "dcc" && ansv.Service == "Main");
var cDRez = ansl.FirstOrDefault(ansv => ansv.Name == "dcc" && ansv.Service == "DB");
var dSRez = ansl.FirstOrDefault(ansv => ansv.Name == "ddc" && ansv.Service == "Main");
var dDRez = ansl.FirstOrDefault(ansv => ansv.Name == "ddc" && ansv.Service == "DB");
var mSRez = ansl.FirstOrDefault(ansv => ansv.Name == "mc" && ansv.Service == "Main");
var mDRez = ansl.FirstOrDefault(ansv => ansv.Name == "mc" && ansv.Service == "DB");
Just put your query in a private method that takes an Exression and returns Value and call it for each variable (e.g. cDRez, cSRez etc) simply passing different expressions.
private Value GetValue(Expression<Func<MyTable, bool>> filter) {
return MyTable.Where(filter).OrderByDescending(o => o.Time).Select(s => s.Value).FirstOrDefault();
}
Call it like with different filters for each variable:
var cSRez = GetValue(l => l.Name == "dcc" && l.Service == "Main");
var cDRez = GetValue(l => l.Name == "dcc" && l.Service == "DB");
var dSRez = GetValue(l => l.Name == "ddc" && l.Service == "Main");
var dDRez = GetValue(l => l.Name == "ddc" && l.Service == "DB");
var mSRez = GetValue(l => l.Name == "mc" && l.Service == "Main");
var mDRez = GetValue(l => l.Name == "mc" && l.Service == "DB");

c# - Group by and having with two counts in Linq

How can I write the follow query with Linq in C#?
SELECT MAX(A2.LINHA_PLANILHA)
FROM MD_IMP_FORCA_VENDA_DADOS_A2 A2
WHERE A2.LINHA <> '0'
AND TRIM(A2.SETORES) IS NOT NULL
AND A2.LINHA_PLANILHA <> 1
AND USUARIO = V_USUARIO
GROUP BY A2.LINHA, A2.BRICK
HAVING COUNT(A2.BRICK) > 1 AND COUNT(DISTINCT A2.SETORES) > 1;
I thought to do this:
var result = from r in dataTable.AsEnumerable()
where r.Field<string>(1) != "0"
&& r.Field<string>(2).Trim() != null
&& r.Field<Int32>(0) != 1
group r by new {Linha = r.Field<string>(1), Brick = r.Field<string>(3) } into temp
where temp.Count() > 1
select new { MaxLinha = (from r2 in temp select r2.Field<Int32>(0)).Max()};
But I don't know how to put the two COUNTS of HAVING clause in Linq query.
Any help would be appreciated.
Thanks
Zago
Perhaps:
var query = db.MD_IMP_FORCA_VENDA_DADOS_A2
.Where(x => x.LINHA != "0"
&& x.SETORES != null
&& x.SETORES.Trim() != ""
&& x.LINHA_PLANILHA <> 1
&& x.USUARIO = x.V_USUARIO
)
.GroupBy(x => new { x.LINHA, x.BRICK })
.Where(g => g.Count() > 1 && g.Select(x => x.SETORES).Distinct().Count() > 1)
.Select(g => g.Max(x => x.LINHA_PLANILHA));

Linq:How to make this easy with one line code?

Forget most learnt about linq,now need to review what is it. And how it works.now I need help for this. Please help me .Thank you so much.
var everyMonthMoneySum = new EveryMonthMoneySum()
{
M_01 = (from o in temp.Where(o => o.IsSign == (short) OrderStateEnum.Success && o.SignMonth == 1)
select o.Signmoney).Sum(),
M_02 = (from o in temp.Where(o => o.IsSign == (short) OrderStateEnum.Success && o.SignMonth == 2)
select o.Signmoney).Sum(),
M_03 = (from o in temp.Where(o => o.IsSign == (short) OrderStateEnum.Success && o.SignMonth == 3)
select o.Signmoney).Sum(),
M_04 = (from o in temp.Where(o => o.IsSign == (short) OrderStateEnum.Success && o.SignMonth == 4)
select o.Signmoney).Sum(),
M_05 = (from o in temp.Where(o => o.IsSign == (short) OrderStateEnum.Success && o.SignMonth == 5)
select o.Signmoney).Sum()+5,
...........................
M_11 = (from o in temp.Where(o => o.IsSign == (short) OrderStateEnum.Success && o.SignMonth == 11)
select o.Signmoney).Sum(),
M_12 = (from o in temp.Where(o => o.IsSign == (short) OrderStateEnum.Success && o.SignMonth == 12)
select o.Signmoney).Sum()
};
It sounds to me like you could do with a dictionary:
var results = temp.Where(o => o.IsSign == (short) OrderStateEnum.Success)
.GroupBy(o => o.SignMonth)
.ToDictionary(g => g.Key, g => g.Sum(o => o.SignMoney));
Note that that won't populate the dictionary with entries for "missing" months.
That will give you a single collection, instead of 12 different variables. Personally I find that's usually a better approach, but we don't really know what you're trying to do with those 12 values...
If you want to make sure the dictionary is populated, I would personally do that with an extra loop afterwards:
for (int i = 1; i <= 12; i++)
{
if (!results.ContainsKey(i))
{
results[i] = 0m;
}
}
It's not "clever", but it works. Alternatively, you could populate an array from the dictionary:
var array = new decimal[13]; // 0 to 12 *inclusive*
foreach (var entry in array)
{
array[entry.Key] = entry.Value;
}
There are other ways of doing it all in the LINQ statement, but I don't know how they'd play with whatever LINQ provider you're using (we don't know) and they're more complex.
Use GroupBy and Where to filter out the values and then group by SignMonth like:
var query = temp.Where(o => o.IsSign == (short) OrderStateEnum.Success)
.GroupBy(r => r.SignMonth)
.Select(grp => new
{
Month = grp.Key,
Sum = grp.Sum(t => t.Signmoney)
});

Categories