Calculating product's quantity with nested EF Query - c#

I want to calculate the quantity of every product. I want to use these tables for this.
I want take result like this.
StockId | StockName | Sum(ProductNumber) [actually product quantity]
I tried this code for can take right result but It is returning null value even though it is the condition that satisfies the conditions.
CimriContext context = new CimriContext();
public ICollection<StockDto.StockHeader> FillDataGrid(int userCompanyId)
{
ICollection<StockDto.StockHeader> Stocks = context.Stocks.Where(c => c.UserCompanyId==userCompanyId).
Select(c => new StockDto.StockHeader()
{
StockId = c.StockId,
StockName = c.StockName,
Piece=0
}).ToList();
ICollection<StockDto.StockHeader> ProductHeader = new List<StockDto.StockHeader>();
foreach (var products in Stocks)
{
products.Piece = context.ProductTransactions.Where(p => p.StockId==products.StockId).Sum(s => s.ProductNumber);
ProductHeader.Add(products);
}
return ProductHeader.ToList();
}

You want to retrieve ProductCount for per stock record. You can perform it by joining two tables and grouping StockId and StockNumber like this;
var query = from stocks in context.Stocks
join products in context.ProductTransactions ON stocks.StockId equals products.StockId
where stocks.UserCompanyId = userCompanyId
group stocks by new
{
stocks.StockId,
stocks.StockName
} into gcs
select new
{
StockId = gcs.Key.StockId,
StockName = gcs.Key.StockName,
ProductCounts = gcs.Count()
};

Related

Not getting expected rows after inner joins after joining two data tables

I'm joining two data tables on composite key i.e account no. and amount but according pictures I've attached I'm getting only one row after join but I should get 2 rows.
var query = from dataRows1 in clearingDTAlias.AsEnumerable()
join dataRows2 in excelDT.AsEnumerable()
on new
{
Account_No = dataRows1.Field<string>("Account_No"),
Amount = dataRows1.Field<string>("Withdraw_Amount_Requested")
} equals new
{
Account_No = dataRows2.Field<string>("Account_No"),
Amount = dataRows2.Field<string>("Amount")
}
select joinDT.LoadDataRow(new object[]
{
dataRows2.Field<string>("Account_No"),
dataRows2.Field<string>("Amount"),
dataRows2.Field<string>("Code"),
dataRows2.Field<string>("Row_No"),
}, true);
if (query.Any())
{
var query2 = query.GroupBy(test => test.Field<string>("Row_No")).Select(grp => grp.First()).ToList();
if (query2.Any())
joinDT = query2.CopyToDataTable();
else
joinDT = excelDT.Clone();
}
Use below group by clause to get the grouped rows from query.
var query2 = query.GroupBy(test => test.Field<string>("Row_No"))
.Select(grp => grp.Key).ToList()

C# SELECT GROUP by SUM LINQ

I have some tables which i am joining with LINQ, this is one of the first times using it so im not that familiar with it.
The next query is as:
var query = from catalogoV in catalogo_DT.AsEnumerable()
where catalogoV.Field<String>("Incluye GPS") == "yes"
join vehicle in vehicleData.AsEnumerable()
on catalogoV.Field<String>("Numero Economico") equals vehicle.Field<String>("DisplayName")
join actividad in activityData.AsEnumerable()
on vehicle.Field<Guid>("VehicleId") equals actividad.Field<Guid>("VehicleId")
select new {Displayname = catalogoV.Field<String>("Numero Economico"), ID = vehicle.Field<Guid>("VehicleId"), Increment = actividad.Field<Single>("IncrementalDistance") };
This is an example of the results i get
{ Displayname = "0DNP-625", ID = {651e5858-bc54-4459-a5de-31144eed3374}, Increment = 0.1 }
{ Displayname = "0DNP-625", ID = {651e5858-bc54-4459-a5de-31144eed3374}, Increment = 0.4 }
{ Displayname = "0DNP-625", ID = {651e5858-bc54-4459-a5de-31144eed3374}, Increment = 4.5 }
{ Displayname = "0003-333", ID = {ecb42206-397f-4cff-bf53-4aac8877491c}, Increment = 0.5 }
{ Displayname = "0003-333", ID = {ecb42206-397f-4cff-bf53-4aac8877491c}, Increment = 5.2 }
But i really want to get the sum of increment back and not all the rows for it.
such as:
{ Displayname = "0003-333", ID = {ecb42206-397f-4cff-bf53-4aac8877491c}, Increment = 5.7 }
{ Displayname = "0DNP-625", ID = {ecb42206-397f-4cff-bf53-4aac8877491c}, Increment = 5.0 }
From what i have read i need to place a gorup in my statement but i dont know how i should mix it with my select, and i cant find something like this on the reference MSDN
You probably need to use a group join, rather than just join, for the actividad field. Here's how:
var query =
from catalogoV in catalogo_DT.AsEnumerable()
where catalogoV.Field<String>("Incluye GPS") == "yes"
join vehicle in vehicleData.AsEnumerable()
on catalogoV.Field<String>("Numero Economico") equals vehicle.Field<String>("DisplayName")
join actividad in activityData.AsEnumerable()
on vehicle.Field<Guid>("VehicleId") equals actividad.Field<Guid>("VehicleId")
into actividads
let ID = vehicle.Field<Guid>("VehicleId")
orderby ID
select new
{
Displayname = catalogoV.Field<String>("Numero Economico"),
ID,
Increment = actividads.Sum(x => x.Field<Single>("IncrementalDistance"))
};
I've added ordering as per your comment.

Compare with list using linq

I have a list cids that I am fetching like this
var cids = _service.Employee.Where(i => i.EmpID == _empID).Select(j => j.ClientID).ToList();
I want to compare this list with Patient Entity and get all the records of patients that matches the clientId in the cid list
Patient Entity is like this
class Patient
{
Int PatientID{ get; set;}
Int ClientID{get; set;}
string PatientName{get; set;}
}
Right now I am doing it like this
foreach(var item in cids)
{
var pp = from p1 in _service.Patients
where p1.ClientId == item
select new PatientDTO
{
PatientID = p1.PatientID,
PatientName = p1.PatientName,
};
prec.Add(pp);
}
Is there a way to do it with Linq without using foreach
You can use Contains on your List (you don't need the ToList, by the way : this would avoid 2 queries on db).
var allPp = _service.Patients.Where(p1 => cids.Contains(p1.ClientId))
.Select(m >= new PatientDTO) {
PatientID = m.PatientID,
PatientName = m.PatientName
});
But the most performant way, in a db world, would be a join
from emp in _service.Employee.Where(i => i.EmpID == _empID)
join patient in _service.Patients on emp.ClientId equals patient.ClientId
select new PatientDTO {
PatientID = patient.PatientID,
PatientName = patient.PatientName,
}
Use Enumberable.Intersect to fetch common records.
var commonClients = cids.Intersect<int>(_service.Patients.Select(x => x.ClientID));
var person = _service.Patients.Where(x => commonClients.Contains(x.ClientID));

Linq query to sum values from tables

I have a LINQ query, which takes an invoice, looks up the quantity and unit price of each item attached, and in another linked table, looks up any payments made against the invoice.
Currently this is:
from i in Invoices
select new
{
i.InvoiceId, i.CustomerName,
Items =
from it in InvoiceItems
where i.InvoiceId == it.InvoiceId
select new {
it.Item,
it.Quantity,
it.UnitPrice,
SubPrice=it.Quantity*it.UnitPrice
},
Payments =
from pi in PaymentInvoices
where i.InvoiceId == pi.InvoiceId
select new {
SumPayments=pi.AmountAllocated
}
}
This shows the following results:
How do I change this LINQ query to show just the sum of SubPrice and SumPayments (ie:
Invoice 11: SubPrice= 90.00 SumPayments= 24.00
Invoice 12: SubPrice=175.00, SumPayments=175.00
Thank you for any help,
Mark
UPDATE SHOWING WORKING ANSWER FOLLOWING ANSWER FROM KENNETH
from i in Invoices
select new
{
InvoiceID = i.InvoiceId,
CustomerName = i.CustomerName,
SubPrice = InvoiceItems.Where(it => it.InvoiceId == i.InvoiceId).Select(it => it.Quantity*it.UnitPrice).Sum(),
SumPayments = PaymentInvoices.Where(pi => pi.InvoiceId == i.InvoiceId).Select(pi => pi.AmountAllocated).Sum()
}
You could use the following method:
from i in Invoices
select new
{
InvoiceID = i.InvoiceId,
CustomerName = i.CustomerName,
SubPrice = InvoiceItems.Where(it => it.InvoiceID = i.InvoiceID).Select(it => it.Quantity*it.UnitPrice).Sum(),
SumPayments = PaymentInvoice.Where(pi => pi.InvoiceId = i.InvoiceId).Select(pi => pi.AmountAllocated).Sum()
}

Nested ForEach loop to Linq

I am trying to convert below nested for each loop into Linq. However I am still unable to do it successfully.
var objAct = new List<InformaticsBenchmarkSummary>();
foreach (var item in op)
{
foreach (var lstTp5 in lstTopFive)
{
if (item.UnitOfOperations.ContainsKey(lstTp5.SystemID))
{
var objIbm = new InformaticsBenchmarkSummary();
objIbm.CompanyId = item.CompanyId;
objIbm.CompanyName = item.CompanyName;
objIbm.LocationId = item.LocationId;
objIbm.LocationName = item.LocationName;
objIbm.UnitOfOperations.Add(lstTp5.SystemID,
item.UnitOfOperations[lstTp5.SystemID]);
objAct.Add(objIbm);
}
}
}
Where UnitOfOperations is of type Dictionary<int,string>();
op is again List<InformaticsBenchmarkSummary>()
lstTopFive is List<int>()
I tried, something like this but was unsuccessful syntactically
var output = from item in op
from lstTp5 in lstTopFive
where item.UnitOfOperations.ContainsKey(lstTp5.SystemID)
let v = new InformaticsBenchmarkSummary()
{
CompanyId = item.CompanyId,
CompanyName = item.CompanyName,
LocationId = item.LocationId,
LocationName = item.LocationName
}
.UnitOfOperations.Add(lstTp5.SystemID, item.UnitOfOperations[lstTp5.SystemID])
select v;
Nested loop works perfectly but I think, linq on this will increase performance.
Appreciate any help.
It is impossible in a Linq query-syntax to use the UnitOfOperations.Add in the select. But you can do it using Method Chain and a SelectMany method:
var objAcu = (op.SelectMany(item => lstTopFive, (item, lstTp5) => new { item, lstTp5 }) // <- Bad readability
.Where(t => t.item.UnitOfOperations.ContainsKey(t.lstTp5.SystemID))
.Select(t =>
{
var objIbm = new InformaticsBenchmarkSummary
{
CompanyId = t.item.CompanyId,
CompanyName = t.item.CompanyName,
LocationId = t.item.LocationId,
LocationName = t.item.LocationName
};
objIbm.UnitOfOperations.Add(t.lstTp5.SystemID, t.item.UnitOfOperations[t.lstTp5.SystemID]);
return objIbm;
})).ToList();
If the property UnitOfOperations has a public set, in this case, you can use the query-syntax.
How do you replace 1 foreach? By a from ... in ...
Then, to replace 2 foreach, use 2 from ... in ...
var objAct = (from item in op // First foreach loop
from lstTp5 in lstTopFive // Second foreach loop
where item.UnitOfOperations.ContainsKey(lstTp5.SystemID)
select new InformaticsBenchmarkSummary
{
CompanyId = item.CompanyId,
CompanyName = item.CompanyName,
LocationId = item.LocationId,
LocationName = item.LocationName,
UnitOfOperations = { { lstTp5.SystemID, item.UnitOfOperations[lstTp5.SystemID] } }
}).ToList();
But I doubt it will increase performance in such an operation.
Anyway, I don't understand what you try to achieve. Because in all items of the output will have one and only one element in the dictionary UnitOfOperations. Is it really what you want to do?
UPDATE
List<int> systemIdTop5 = lstTopFive.Select(tp5 => tp5.SystemID).ToList();
var objAct = (from item in op
select new InformaticsBenchmarkSummary
{
CompanyId = item.CompanyId,
CompanyName = item.CompanyName,
LocationId = item.LocationId,
LocationName = item.LocationName,
UnitOfOperations = systemIdTop5.Intersect(item.UnitOfOperations.Keys)
.ToDictionary(systemId => systemId, systemId => item.UnitOfOperations[systemId])
}).ToList();
As far as I can tell it is your UnitOfOperations that you're having difficulty with. If it is initialized in the constructor you can use this:
var output = from item in op
from lstTp5 in lstTopFive
where item.UnitOfOperations.ContainsKey(lstTp5.SystemID)
select
new InformaticsBenchmarkSummary()
{
CompanyId = item.CompanyId,
CompanyName = item.CompanyName,
LocationId = item.LocationId,
LocationName = item.LocationName,
UnitOfOperations = { { lstTp5.SystemID, item.UnitOfOperations[lstTp5.SystemID] } }
};
The result is an IEnumerable, if you want it as a list, call output.ToList().
Two side notes:
I don't believe this will be any quicker. It is still a inner loop.
This might produce almost duplicate items in the result (different UnitOfOperations), but I guess that is desired. In the worst case scenario all items in op have a UnitOfOperations that contain all the SystemID in lstTopFive giving us a total of op.Count()*lstTopFive.Count() items in the output.
You're close, but you can't just use a void returning method in LINQ query like that. (And if it wasn't void-returning, then v would be the result of Add(), which would be most likely wrong.)
If you wanted to create a new Dictionary for UnitOfOperations, you could set it the same way as other properties. But if you can't do that (probably because UnitOfOperations has a private setter) or you don't want to (because UnitOfOperations is initialized to some value that you want to keep), you can use a lesser known feature of C#: collection initializer inside object initializer:
UnitOfOperations = { { lstTp5.SystemID, item.UnitOfOperations[lstTp5.SystemID] } }
The effect of this code is the same as if you wrote:
createdObject.UnitOfOperations.Add(lstTp5.SystemID, item.UnitOfOperations[lstTp5.SystemID]);
The only difference is that it's not a statement, it's part of an expression, which means you can use it in a LINQ query.
The whole query would then be:
var output = from item in op
from lstTp5 in lstTopFive
where item.UnitOfOperations.ContainsKey(lstTp5.SystemID)
select new InformaticsBenchmarkSummary()
{
CompanyId = item.CompanyId,
CompanyName = item.CompanyName,
LocationId = item.LocationId,
LocationName = item.LocationName,
UnitOfOperations =
{
{ lstTp5.SystemID, item.UnitOfOperations[lstTp5.SystemID] }
}
};
May this help U :
var output = from item in op
join lstTp5 in lstTopFive on item.UnitOfOperations.Key equals lstTp5.SystemID
select new InformaticsBenchmarkSummary
{
CompanyId = item.CompanyId,
CompanyName = item.CompanyName,
LocationId = item.LocationId,
LocationName = item.LocationName,
UnitOfOperations = item.UnitOfOperations
};

Categories