.Sum() in lambda expressions - c#

I'm new to lambda expressions. I'm trying to use the .Sum() method to a result from a db search, I want to sum all the values from the Importe column, I'm selecting the values using an ID from another table, but the Json send me back the entire list with every value, it's not doing the sum. Or maybe I don't know how to apply it?
Thank you
public JsonResult IngresaCuentas(string codigo)
{
ContextoAngeles db = new ContextoAngeles();
var suma = (from data in db.Cuentas
where data.Codigo == codigo
select (from n in db.MovimientosPolizas
where data.Id == n.IdCuenta
group n by new { n.Importe} into g
let sumaTotal = (g.Sum(n => n.Importe))
select new
{
Total: sumaTotal
})).ToList();
return Json(suma, JsonRequestBehavior.AllowGet);
}
I'm getting this in the Console:
[[{"Total":0},{"Total":20},{"Total":150},{"Total":330},{"Total":56.2},{"Total":240},{"Total":1750},{"Total":70.07},{"Total":480},{"Total":540},{"Total":95},{"Total":200},{"Total":108},{"Total":108.8},{"Total":880},{"Total":111.98},{"Total":115},{"Total":240},{"Total":125},{"Total":129.98},{"Total":780},{"Total":131.42},{"Total":134.59},{"Total":1260},{"Total":141.65},{"Total":145}]] (and a lot more..)

A friend helped me to resolve this issue and a Join was the answer. I think i didn't explain my problem clear enough, I was trying to do that but in a different way more like SQL syntax, if anyone knows a good place to learn about lambda expressions would be great.
Thank all of you! Here the solution.
var dato = db.Cuentas.Where(x => x.Codigo == codigo)
.Join(db.MovimientosPolizas, cuentas => cuentas.Id, movimientos => movimientos.IdCuenta, (cuenta, movimiento) => new { sumImporte = movimiento.Importe, cuenta = cuenta.Nombre })
.Sum(x => x.sumImporte);

When you are using select new { Total: sumaTotal }, that's not just sending back the int, that's sending you an object of an anonymous type with a Total field. I don't think that that's what you're going after.
What I think you should be doing is something like this:
var suma = (from data in db.Cuentas
where data.Codigo == codigo
select (from n in db.MovimientosPolizas
where data.Id == n.IdCuenta
group n by new { n.Importe} into g
let sumaTotal = (g.Sum(n => n.Importe))
select sumaTotal)).ToList();
Or, if what you're going for is to select the sum of every Importe that you've queried:
var suma = (from data in db.Cuentas
where data.Codigo == codigo
select (from n in db.MovimientosPolizas
where data.Id == n.IdCuenta
group n by new { n.Importe} into g
let sumaTotal = (g.Sum(n => n.Importe))
select sumaTotal)).Sum();

Related

Join + Group + Aggregate in LINQ

I have the following query, which I put into a DataGrid:
var balancePerAccount = from bal in data.balanceDetails
join acc in data.userPaymentDetails on bal.userName equals acc.userName
where bal.paymentID == 0
group bal by bal.userName into g
where g.Sum(p => p.rebateBeforeService) >= 20
select new
{
Username = g.Key,
Amount = g.Sum(p => p.rebateBeforeService),
};
dgPaymentsPending.DataSource = balancePerAccount;
dgPaymentsPending.DataBind();
What I would like to do is add something inside acc in to the select. For example I would like to add PaymentProvider = acc.PaymentProvider. I tried flipping this every way I could think of, including getting First() from the group and trying to access it from there, but I can't seem to find a way to access it. I might just be missing something really simple, but I have been looking around Google for some time and I can't seem to find a comparable example. Anyone have an idea?
Extend grouping source using anonymous type: new { bal, acc } and then use First
var balancePerAccount = from bal in data.balanceDetails
join acc in data.userPaymentDetails on bal.userName equals acc.userName
where bal.paymentID == 0
group new { bal, acc } by bal.userName into g
where g.Sum(p => p.bal.rebateBeforeService) >= 20
select new
{
Username = g.Key,
PaymentProvider = g.FirstOrDefault().acc.PaymentProvider,
Amount = g.Sum(p => p.bal.rebateBeforeService),
};

How do I return data presorted after grabbing them inside a foreach loop?

First, I'm grabbing ClientID. Then, I get all Invoices associated with that ClientID. I want to return data all ordered by InvoiceNumber, descending. Here's my code:
var rvInvoices =
(from i in db.QB_INVOICES_HEADER
where i.ClientID == cId
select i).ToList();
foreach (var itm in rvInvoices)
{
InvoiceModel cm = new InvoiceModel()
{
InvoiceNumber = itm.InvoiceNumber,
InvoiceSentDt = itm.InvoiceSentDt,
InvoiceDt = itm.InvoiceDt,
Amount = itm.Amount,
Term = itm.Term,
ClientName = itm.CI_CLIENTLIST.ClientName
};
listInvoices.Add(cm);
}
return listInvoices;
listInvoices.OrderByDescending(x => x.InvoiceNumber).ToList()
You should try something like this:
var rvInvoices =
(from i in db.QB_INVOICES_HEADER
where i.ClientID == cId
select i).OrderByDescending(x => x.InvoiceNumber);
And I don't see a reason you need to call .ToList().
You can do the order in three places.
In the initial query,
In the foreach, or
In the return
Option 1:
var rvInvoices =
(from i in db.QB_INVOICES_HEADER
where i.ClientID == cId
select i).OrderByDescending(i => i.InvoiceNumber).ToList();
Option 2:
foreach (var itm in rvInvoices.OrderByDescending(i => i.InvoiceNumber))
Option 3:
return listInvoices.OrderByDescending(i => i.InvoiceNumber).ToList();
I would suggest taking route 1 since it will run the order at the database level.
You should order them on the database instead of the client:
var rvInvoices = db.QB_INVOICES_HEADER
.Where(i => i.ClientID == cId)
.OrderByDescending(i => i.InvoiceNumber);
The method you currently have creates multiple lists, has an explicit foreach loop, and needs to have its output sorted. It can be done with just creating a single list, no explicit looping, and with the database doing the sorting for you:
return
(from i in db.QB_INVOICES_HEADER
where i.ClientID == cId
// have the database do the sorting
orderby i.InvoiceNumber descending
select i)
// break out of the DB query to make InvoiceModel
.ToEnumerable()
.Select(itm => new InvoiceModel()
{
InvoiceNumber = itm.InvoiceNumber,
InvoiceSentDt = itm.InvoiceSentDt,
InvoiceDt = itm.InvoiceDt,
Amount = itm.Amount,
Term = itm.Term,
ClientName = itm.CI_CLIENTLIST.ClientName
})
// only create one list as the last step
.ToList();

LINQ Join to get latest record from 2nd table

Problem:
Their are two tables TableEmails and TableSentEmailRecords. So when ever emails are sent out, a records, such as sent time etc are stored in TableSentEmailRecords.
I want to do a LINQ query, which gets me columns of TableEmails PLUS a "SentDate" column from TableSentEmailRecords that displays the latest date that email was sent out.
I tried this:
List<CustomEmail> emails = new List<CustomEmail>();
var query = from c in db.TableEmails
join o in db.TableSentEmailRecords on c.EmailId equals o.EmailId
select new CustomEmail
{
EmailName = c.EmailName,
EmailId= c.EmailId,
EmailDescription = c.EmailDescription,
LastDateEmailSentOut = o.SentDate
};
emails = query.ToList();
but this not necessarily get the latest record of that particular email from TableSentEmailRecords table.
Any Ideas ???
You could just use a nested query instead of the join:
var query = from c in db.TableEmails
select new CustomEmail
{
EmailName = c.EmailName,
EmailId= c.EmailId,
EmailDescription= c.EmailDescription,
LastDateEmailSentOut = db.TableSentEmailRecordson
.Where(x => x.EmailId = c.EmailId)
.Max(x => x.SentDate)
};
I think GroupJoin is the correct method in this case. Using a sub query will work but it is not going to be as efficient. Sorry, I don't know the simpler query syntax that well and especially I don't know how to do group join with it. Maybe someone can translate.
db.TableEmails.GroupJoin(db.TableSendEmailRecordson,
o => o.EmailID,
i => i.EmailID,
(o, i) => new
{
EmailName = c.EmailName,
EmailId= c.EmailId,
EmailDescription= c.EmailDescription,
LastDateEmailSentOut = i.Max(x => x.SentDate)
})
To get all the details from TableSendEmailRecordson you could do something like this:
db.TableEmails.GroupJoin(db.TableSendEmailRecordson,
o => o.EmailID,
i => i.EmailID,
(o, i) => new
{
EmailName = c.EmailName,
EmailId= c.EmailId,
EmailDescription = c.EmailDescription,
LastSendEmailRecordson = i.FirstOrDefault(y => y.SentDate == i.Max(x => x.SentDate))
})
That may complain about being translated to SQL, if that is the case then you need to first get the data and then use the results in the query, eg
var emails = db.TableEmails.ToArray();
var emailSend = db.TableSendEmailRecordson.ToArray();
you can try something like this:
var query = (from c in db.TableEmails
join o in db.TableSentEmailRecordson c.EmailId equals o.EmailId
select new CustomEmail
{
EmailName = c.EmailName,
EmailId = c.EmailId,
EmailDescription = c.EmailDescription,
LastDateEmailSentOut = o.SentDate
}).OrderByDescending(c => c.LastDateEmailSentOut).ToList();

Linq to SQL join and group

I have two tables in my database:
Town:
userid, buildingid
Building:
buildingid, buildingname
What i want is to populate a GridView like this:
But I don't want the buildings to be shown more than once. Here is my code:
var buildings = dc.Towns
.Where(t => t.userid == userid)
.GroupJoin(dc.Buildings,
t => t.buildingid,
b => b.buildingid,
(Towns, Buildings) => new
{
BuildningName = Buildings.First().buildingname,
Count = Towns.Building.Towns.Count()
});
gvBuildings.DataSource = buildings.ToList();
gvBuildings.DataBind();
New code which works:
var buildings = (from t in dc.Towns
where t.userid == userid
join b in dc.Buildings
on t.buildingid equals b.buildingid
into j1
from j2 in j1.DefaultIfEmpty()
group j2 by j2.buildingname
into grouped
select new
{
buildingname = grouped.Key,
Count = grouped.Count()
});
gvBuildings.DataSource = buildings.ToList();
gvBuildings.DataBind();
var buildings = from t in dc.Towns
join b in dc.Buildings on t.buildingid equals b.buildingid into j1
from j2 in j1.DefaultIfEmpty()
group j2 by b.buildingname into grouped
select new { buildingname = grouped.key, Count = grouped.Count()}
I think this should do it. I have not tested it so it might give error but it will be something like this.
Wouldn't something like this do it?
Users
.Select(User => new {User, User.Building})
.GroupBy(x => x.Building)
.Select(g=> new {Building = g.Key, Count = g.Count()})
According to my experience with Linq to SQL, when the expression is becoming complicated it is better to write a stored procedure and call it with Linq to SQL. In this way you get better maintainability and upgradeability.
Rather than an option to pure SQL, I see “Linqu to SQL” as a tool to get hard typed object representation of SQL data sets. Nothing more.
Hope it helps you.

LINQ to SQL omit field from results while still including it in the where clause

Basically I'm trying to do this in LINQ to SQL;
SELECT DISTINCT a,b,c FROM table WHERE z=35
I have tried this, (c# code)
(from record in db.table
select new table {
a = record.a,
b = record.b,
c = record.c
}).Where(record => record.z.Equals(35)).Distinct();
But when I remove column z from the table object in that fashion I get the following exception;
Binding error: Member 'table.z' not found in projection.
I can't return field z because it will render my distinct useless. Any help is appreciated, thanks.
Edit:
This is a more comprehensive example that includes the use of PredicateBuilder,
var clause = PredicateBuilder.False<User>();
clause = clause.Or(user => user.z.Equals(35));
foreach (int i in IntegerList) {
int tmp = i;
clause = clause.Or(user => user.a.Equals(tmp));
}
var results = (from u in db.Users
select new User {
a = user.a,
b = user.b,
c = user.c
}).Where(clause).Distinct();
Edit2:
Many thanks to everyone for the comments and answers, this is the solution I ended up with,
var clause = PredicateBuilder.False<User>();
clause = clause.Or(user => user.z.Equals(35));
foreach (int i in IntegerList) {
int tmp = i;
clause = clause.Or(user => user.a.Equals(tmp));
}
var results = (from u in db.Users
select u)
.Where(clause)
.Select(u => new User {
a = user.a,
b = user.b,
c = user.c
}).Distinct();
The ordering of the Where followed by the Select is vital.
problem is there because you where clause is outside linq query and you are applying the where clause on the new anonymous datatype thats y it causing error
Suggest you to change you query like
(from record in db.table
where record.z == 35
select new table {
a = record.a,
b = record.b,
c = record.c
}).Distinct();
Can't you just put the WHERE clause in the LINQ?
(from record in db.table
where record.z == 35
select new table {
a = record.a,
b = record.b,
c = record.c
}).Distinct();
Alternatively, if you absolutely had to have it the way you wrote it, use .Select
.Select(r => new { a = r.a, b=r.b, c=r.c }).Distinct();
As shown here LINQ Select Distinct with Anonymous Types, this method will work since it compares all public properties of anonymous types.
Hopefully this helps, unfortunately I have not much experience with LINQ so my answer is limited in expertise.

Categories

Resources