Linq query to sum values from tables - c#

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

Related

LINQ with JOIN, GROUP, SUM() and return a new SELECT

it is possible to perform a LINQ like this SQL:
select invoice.credit, ((sum(detailsInvoice.amount) - sum(detailsInvoice.discount))+ sum(detailsInvoice.tax)) as total
from detailsInvoice
join invoice on detailsInvoice.invoiceID = invoice.ID
where invoice.carga = 1428 and invoice.ID <> 0
group by invoice.credit
I'm getting this result in the SQL
I spend so much time trying to create a LINQ to perform that query, without luck.
you should do something like this, please excuse any typo errors, didn't use a compiler to test it.
var result = db.invoice.Include(x=>x.detailsInvoice).
GroupBy(x=>invoice.credit).
Select(y=> new {
credit = y.Key,
Total = (y.Sum(z=>z.detailsInvoice.amount) - y.Sum(z=>z.detailsInvoice.discount) + y.Sum(z=>detailsInvoice.tax))
});
Hope this helps!
your answer gave me a good idea of what to do.
something important I forgot to mention is the Invoice table and detailsInvoice don't have a relationship.
So this is what I did:
var result = (from _invoice in ruterosContext.Invoice
join _details in ruterosContext.DetailsInvoice
on new { id = _invoice.ID, reference = _invoice.Reference } equals
new { id = _details.invoiceID, reference = _details.Reference }
where _invoice.ID != 0 && _invoice.Carga == 1428
select new {
Credit = _invoice.credit,
amount = _details.amount,
discount = _details.discount,
tax = _details.tax
}).GroupBy(x => x.credit).
Select(y => new { Credit = y.Key,
Total = (y.Sum(z => z.amount) - y.Sum(z => z.discount)) + y.Sum(x => x.tax) });

Calculating product's quantity with nested EF Query

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

How to calculate amount sum for every single product in every single quarter using linq?

I have a data table with release plans for every product:
I'd like to calculate amount sum for every single product in every single quarter using linq. In SQL I'd use:
How can I do that in linq?
I tried this code:
public List<ValuePairPlanned> GetQuantityOfEachProductPlannedForRelease(int departmentId)
{
var amountByProducts = (from rp in _context.ReleasePlans
join p in _context.Products
on rp.ProductProductId equals p.ProductId
where rp.DepartmentDepartmentId == departmentId
group new { rp, p } by new { rp.ProductProductId, p.ProductId, p.ProductName, rp.DateTime, rp.Amount }
into grp
select new
{
grp.Key.ProductName,
grp.Key.DateTime,
PlannedAmount = grp.Sum(g => g.rp.Amount)
}).Distinct().ToList().ConvertAll(x => new ValuePairPlanned()
{ PlannedAmount = x.PlannedAmount, Quarter = (x.DateTime.AddDays(2).Month - 1) / 3 + 1, ProductName = x.ProductName });
return amountByProducts;
}
but as a result I get amount value for every products in every quarter. How can I fix it? Thanks for any help.
Since you are using Entity Framework, look into DbFunctions so that you can do the date addition on the SQL Server. If you do not use DbFunctions, then you will have to first fetch your joined tables via ToList() and then do the data math to calculate quarter.
The following should get you very close:
var amountByProducts = from p in _context.Products
join rp in _context.ReleasePlans
on p.ProductId equals rp.ProductId
where rp.DepartmentDepartmentId == departmentId
group new
{
p.ProductName,
Quarter = (DbFunctions.AddDays(rp.DateTime,2).Month - 1) / 3 + 1,
rp.Amount
}
// group all product plans in a given quarter
by new
{
p.ProductName, // shouldn't this be ProductId?
Quarter = (DbFunctions.AddDays(rp.DateTime,2).Month - 1) / 3 + 1
}
into grp
// from the grouped entries, sum the amounts
select new ValuePairPlanned()
{
PlannedAmount = grp.Sum(g => g.Amount),
Quarter = grp.Key.Quarter,
ProductName = grp.Key.ProductName
};
return amountByProducts.ToList();

LINQ Sum with GroupBy

(Not sure if I even need GroupBy)
My (simplified) tables:
Products (ProductID, Name, Code)
Invoices (InvoiceID, Number, IsPaid)
Invoices_Products (InvoiceID, ProductID, Quantity, Price) - the many-to-many linking table
I need to show a list of Invoices_Products of paid Invoices grouped by the Product Code which sums (Quantity*Price).
The code that I first use to get a collection that I can bind to the UI:
IEnumerable<Invoices_Products> invoices_products = db.Invoices_Products
.Where(ip => ip.Invoice.IsPaid).DistinctBy(m => m.Product.Code);
I then iterate through this to bind it to the UI:
List<BindableInvoiceProduct> bindableInvoiceProducts =
new List<BindableInvoiceProduct>();
foreach (var item in invoices_products)
{
decimal salesValue = db.Invoices_Products.Where(ip => ip.Invoice.IsPaid
&& ip.Product.Code == item.Product.Code).Sum(m => (m.Price * m.Quantity));
bindableInvoiceProducts.Add(new BindableInvoiceProduct()
{
A = item.A,
B = item.B,
SalesValue = salesValue.ToString()
});
}
(The DistinctBy method there is from morelinq)
Why does this not total correctly?
edit:
Some data:
Product - ProductID = 1, Name = 123, Code = A
Product - ProductID = 2, Name = 456, Code = A
Invoice - InvoiceID = 1, Number = INV123, IsPaid = True
Invoices_Products - InvoiceID = 1, ProductID = 1, Quantity = 10, Price = 100
Invoices_Products - InvoiceID = 1, ProductID = 2, Quantity = 10, Price = 200
Expected result:
Code = A, SalesValue = 3000
from invoice in invoices
where invoice.IsPaid
from xr in invoice.InvoiceProducts
group xr.Quantity * xr.Price by xr.Product.Code into g
select new {Code = g.Key, SalesValue = g.Sum()};
If you want per invoice, then:
from invoice in invoices
where invoice.IsPaid
from xr in invoice.InvoiceProducts
group xr.Quantity * xr.Price
by new {Code = xr.Product.Code, Invoice = invoice }
into g
select new {
Code = g.Key.Code,
Invoice = g.Key.Invoice,
SalesValue = g.Sum()};
Based on your description I would have written:
var bindableInvoiceProducts = db.Invoices_Products
.Where(ip => ip.Invoice.IsPaid)
.GroupBy(ip => ip.Product.Code,
(code, ips) => new BindableInvoiceProduct()
{
Code = code,
SalesValue = ips.Sum(ip => (ip.Price*ip.Quantity))
})
.ToList();
Is that, what you need? What is item.A and item.B in your code?

Is this the proper way to select the previous and next record given an ID for the current record?

I need to run a LINQ query which will return 3 rows (The current record, Previous record, and the next record relative to the current record. ProductID is my autogenerated identity column.
Currently i'm doing this with a Union LINQ statement but I'm not sure if there is a better or a more efficient way to accomplish the same task.
Here's what I got:
var ProductID = 10;
var Results = (from p in DB.Products
where p.ProductID == ProductID - 1 //Previous record.
select new Product
{
ProductID = p.ProductID,
ProductTitle = p.ProductTitle,
Views = p.Views,
}).Union(from p in DB.Products
where p.ProductID == ProductID //Current record
select new Product
{
ProductID = p.ProductID,
ProductTitle = p.ProductTitle,
Views = p.Views,
}).Union(from p in DB.Products
where p.ProductID == ProductID + 1 //Next record.
select new Product
{
ProductID = p.ProductID,
ProductTitle = p.ProductTitle,
Views = p.Views,
});
This should return 3 rows for ProductID 9, ProductID 10, ProductID 11. Thanks!
Personally I would use this approach:
it has the benefit of working where Ids are missing in the range. A brave man assumes all Ids are accounted for and present.
var currAndNext = Context.Set<TPoco>()
.Where<TPoco>(t=>t.id == id)
.OrderBy(t=>t.id)
.Skip(0)
.Take(2);
var prev = Context.Set<TPoco>()
.Where<TPoco>(t=>t.id == id)
.OrderByDescending(t=>t.id)
.Skip(1)
.Take(1);
Your approach can be rewritten more shortly like this:
var ProductID = 10;
var Results = (from p in DB.Products
where p.ProductID >= ProductID - 1 &&
p.ProductID <= ProductID + 1
select new Product
{
ProductID = p.ProductID,
ProductTitle = p.ProductTitle,
Views = p.Views,
});
But note, this will return what you need only if none of the records corresponding to the specified productIDs have been deleted from the Products table.
GwynBleidd proposed a good solution, however you can also specify a list of IDs, in your case like this:
var ids = new[] {ProductID - 1, ProcuctID, ProductID + 1};
And use it in the where clause
var Results = from p in DB.Products
where ids.Contains(p.ProductID)
select new Product
{
ProductID = p.ProductID,
ProductTitle = p.ProductTitle,
Views = p.Views,
};
I think this is more versatile and EF will translate it to WHERE [ProductID] IN (...), which the query execution planner can handle quite well.
Here's how I would solve the problem -- avoiding the use of +1,-1.
In my case, I was trying to show the previous/next published blog posts. The +1,-1 wouldn't work if the next/prev blog post was unpublished. Not to mention the possibility of Ids not always being consecutive.
In your case, you may not want to show the out of stock products.
var products = db.Products.Where(x => x.Quantity > 0).OrderBy(x => x.ProductId).ToList();
var previous = products.LastOrDefault(x => x.ProductId < id),
var next = products.FirstOrDefault(x => x.ProductId > id)
This will return the previous and next products with the ProductId closest to your starting id.
Note: the .OrderBy(x => x.ProductId) isn't necessary if your list is already in order.
Here was my take on this:
await using var context = new CsuContext(this._csuContextOptions);
var offenseLogs =
context.OffenseLogs ?? throw new Exception("SQL Connection Error");
var last = await offenseLogs.OrderByDescending(log => log.Id)
.FirstOrDefaultAsync()
.ConfigureAwait(false);
if (id == 0) id = last.Id;
var currentAndNext = offenseLogs.Where(log => log.Id >= id)
.OrderBy(log => log.Id)
.Take(2);
var current = await currentAndNext.FirstOrDefaultAsync()
.ConfigureAwait(false);
var next = await currentAndNext.Skip(1)
.FirstOrDefaultAsync()
.ConfigureAwait(false);
var previous = await offenseLogs.Where(log => log.Id <= id)
.OrderByDescending(log => log.Id)
.Take(2)
.Skip(1)
.FirstOrDefaultAsync()
.ConfigureAwait(false);
var first = await offenseLogs.OrderBy(log => log.Id)
.FirstOrDefaultAsync()
.ConfigureAwait(false);
var entry = this._mapper.Map<OffenseLog, OffenseLogDto>(current ??
throw new
Exception($"Could not find entry with id: {id}"));
entry.Next = next?.Id;
entry.Previous = previous?.Id;
entry.First = first.Id != entry.Id ? first.Id : null;
entry.Last = last.Id != entry.Id ? last.Id : null;
return entry;

Categories