LINQ Join to get latest record from 2nd table - c#

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

Related

How to improve Query with linq

I'm a little bit stuck, I took an new project but there is so timeout issue due to queries.
I don't know the syntax in linq to improve one querie even if i tried multiple times.
The query is :
var contactslist = (User as CustomPrincipal).contacts;
var contacts = from m in db.ADDR_DEST.toList()
from n in contactslist
where m.ADDR_COUNTRY == n.country && m.ADDR_TPL_TYPE == n.tpl_type
select m;
But I want to dosen't launch this query before that i had different parametre so i remove the .toList() for adding some condition with
contacts.where(..);
And then I would like launch my query but i got an error with the type which must be an list<> but in this case it's a Iqueryable.
Can you help me please?
Is there an other way to launch this query after I do all my settings?
You can do something like that:
db.ADDR_DEST.Join(contactslist,
addr => new { country = addr.ADDR_COUNTRY, type = addr.ADDR_TPL_TYPE },
cont => new { country = cont.country, type = cont.tpl_type },
(addr, cont) => addr)
.ToList();
Then, if you want to choose the contactlist that meet certain requirements:
db.ADDR_DEST.Join(contactslist.Where(...).ToList(),
addr => new { country = addr.ADDR_COUNTRY, type = addr.ADDR_TPL_TYPE },
cont => new { country = cont.country, type = cont.tpl_type },
(addr, cont) => addr)
.ToList();
I hope you find it useful
Try (not tested):
var contacts = db.ADDR_DEST.Where(m => m.COUNTRY == contactslist.country
&& m.ADDR_TPL_TYPE == contactslist.tpl_type)
.ToList();
If contactslist is a list then try the following
var contacts = (from addr in db.ADDR_DEST
join cl in contactslist on
new {addr.COUNTRY, addr.ADDR_TPL_TYPE} equals new {cl.country, cl.tpl_type}
select new {addr})
.ToList();
The Linq join is easier to understand than its lambda equivalent!
There are some good examples here

Join 2 table and group 2 field in linq

I have a very simple SQL
SELECT s.shop_code
,SUM(im.amt) sum_amt
,s.cell_no#1 shop_cell
FROM tb_sn_so_wt_mst im
,tb_cm_shop_inf s
WHERE im.shop_code = s.shop_code
GROUP BY s.shop_code, s.cell_no#1)
then i try to code linq
var listResult = from warrantyMaster in listWarrantyMasters2.Records
join shopInfo in listShopInfos
on warrantyMaster.ShopCode equals shopInfo.ShopCode
i don't know group by shop code and cell no and sum atm, any one help me out of this problem
The group by syntax with some examples is explained here group clause (C# Reference) and related links.
Here is the direct translation of your SQL query (of course the field names are just my guess since you didn't provide your classes):
var query = from im in listWarrantyMasters2.Records
join s in listShopInfos
on im.ShopCode equals s.ShopCode
group im by new { s.ShopCode, s.CellNo } into g
select new
{
g.Key.ShopCode,
g.Key.CellNo,
SumAmt = g.Sum(e => e.Amt)
};
You can try this code:
var results = from warrantyMaster in listWarrantyMasters2.Records
from shopInfo in listShopInfos
.Where(mapping => mapping.ShopCode == warrantyMaster.ShopCode )
.select new
{
ShopCode = warrantyMaster.ShopCode,
ATM = listWarrantyMasters2.ATM,
ShellNo = shopInfo.ShellNo
}
.GroupBy(x=> new { x.ShopCode, x.ShellNo })
.Select(x=>
new{
ShopCode = x.Key.ShopCode,
ShellNo = x.Key.ShellNo,
SumATM = x.Sum(item=>item.ATM)
});

.Sum() in lambda expressions

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

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