I have the following query in SQL which returns 5 rows of data:
SELECT DISTINCT c.Id, c.FirstName, c.LastName, c.PhoneNumber, 'Waiting to be sent'
FROM DistributionGroupMembers dgm
JOIN Contacts c on dgm.ContactId = c.Id
JOIN DistributionGroups dg on dgm.DistributionGroupId = dg.Id
WHERE dg.Id IN (
SELECT DistributionGroupId
FROM DistributionGroupInSms
WHERE SmsId = 40
)
When I try to run the adequate query in C# using LINQ it won't return anything:
int[] groupIDs = await _db.DistributionGroupInSms.Where(dgis => dgis.SmsId == message.Id).Select(g => g.Id).ToArrayAsync();
var recipients = await (from dgm in _db.DistributionGroupMembers
join c in _db.Contacts on dgm.ContactId equals c.Id
join dg in _db.DistributionGroups on dgm.DistributionGroupId equals dg.Id
where groupIDs.Contains(dg.Id)
select new
{
ID = c.Id,
FN = c.FirstName,
LN = c.LastName,
PN = c.PhoneNumber,
SR = "Waiting to be sent"
}).Distinct().ToListAsync();
What am I doing wrong?
Can you simply do a join:
int[] groupIDs = await _db.DistributionGroupInSms.Where(dgis => dgis.SmsId == message.Id).Select(g => g.Id).ToArrayAsync();
var recipients = await (from dgm in _db.DistributionGroupMembers
join c in _db.Contacts on dgm.ContactId equals c.Id
join dg in _db.DistributionGroups on dgm.DistributionGroupId equals dg.Id
join gIds in groupIDs on gIds equals dg.Id
select new
{
ID = c.Id,
FN = c.FirstName,
LN = c.LastName,
PN = c.PhoneNumber,
SR = "Waiting to be sent"
}).Distinct().ToListAsync();
I figured it out, in the select clause by getting the groupIDs I selected Id instead of another field in the table called DistributionGroupId. Thanks everyone for the input
Related
I have a sample to look into Async calls and i need to get a count from the sub query. I know how to write this in a TSQL query but i am bit confused with the iqueryable use.
Here is what i currently have. I am getting the users and then get the count inside a loop. How can i do the loop part in the first query?
public static async Task GetUsers(this List<UserViewModel> users)
{
var db = ApplicationDbContext.Create();
users.AddRange(await (from u in db.Users
select new UserViewModel
{
Id = u.Id,
Email = u.Email,
FirstName = u.FirstName,
LastName = u.LastName
}).OrderBy(o => o.Email).ToListAsync());
if (users.Any())
{
foreach(var user in users)
{
user.SubscriptionsCount = await (from us in db.UserSubscriptions
join s in db.Subscriptions on us.SubscriptionId equals s.Id
where us.UserId.Equals(user.Id)
select us).CountAsync();
}
}
}
Could be handled in one of the following two ways. I have picked #2 for my sample.
1 : with sub query
var singleQuery = from u in db.Users
join sub in (from us in db.UserSubscriptions
join s in db.Subscriptions on us.SubscriptionId equals s.Id
group us by us.UserId into countGroup
select new { Count = countGroup.Count(), UserId = countGroup.Key })
on u.Id equals sub.UserId into sub1
from subR in sub1.DefaultIfEmpty()
select new UserViewModel
{
Id = u.Id,
Email = u.Email,
FirstName = u.FirstName,
LastName = u.LastName,
SubscriptionsCount = subR.Count == null ? 0 : subR.Count
};
var siteUsersSub = await (query).OrderBy(o => o.Email).ToListAsync();
2: Composing from sub queries
var subQuery = from us in db.UserSubscriptions
join s in db.Subscriptions on us.SubscriptionId equals s.Id
group us by us.UserId into countGroup
select new { Count = countGroup.Count(), UserId = countGroup.Key };
var query = from u in db.Users
join sq in subQuery on u.Id equals sq.UserId into sq1
from sqR in sq1.DefaultIfEmpty()
select new UserViewModel()
{
Id = u.Id,
Email = u.Email,
FirstName = u.FirstName,
LastName = u.LastName,
SubscriptionsCount = sqR.Count == null ? 0 : sqR.Count
};
var siteUsers = await(query).OrderBy(o => o.Email).ToListAsync();
I working on an app with a SQLite database, now I want to select information from multiple tables using linq, here it is what I did:
from c in dataContext.Convention
join e in dataContext.Engineer on c.Engineer equals e.Code
join o in dataContext.Owner on c.Owner equals o.Code
join t in dataContext.ProjectType on c.ProjectType equals t.Id
join cs in dataContext.ConventionState on c.State equals cs.Id
join sc in dataContext.SiteControl on c.Code equals sc.CodeCv
join pc in dataContext.PlanControl on c.Code equals pc.CodeCv
join scs in dataContext.SiteState on sc.State equals scs.Id
join pcs in dataContext.PlanState on pc.State equals pcs.Id
join rcs in dataContext.ReceptionState on sc.Reception equals rcs.Id
join b in dataContext.Bill on c.Code equals b.CodeCv
where cs.Abr == "EC"
group new { c, e, o, t, scs, pcs, rcs, b } by new
{ c.Code, c.NumSeq, c.Year, c.TotalAmount, c.Title, e.LastName, e.FirstName, o.Name,
tprjt = t.Abr,
scState = scs.Abr,
pcState = pcs.Abr,
rcState = rcs.Abr
} into cvgrp
select new
{
Code = cvgrp.Key.Code,
N_Seq = cvgrp.Key.NumSeq,
Exercice = cvgrp.Key.Year,
Intitulé = cvgrp.Key.Title,
Ingenieur = cvgrp.Key.LastName + " " + cvgrp.Key.FirstName,
MaitreOuvrage = cvgrp.Key.Name,
TypeProjet = cvgrp.Key.tprjt,
CtrlPlan = cvgrp.Key.pcState,
CtrlChantier = cvgrp.Key.scState,
Reception = cvgrp.Key.rcState,
Montant = cvgrp.Key.TotalAmount,
MontantFacturé = cvgrp.Sum(x => x.b.Amount),
MontantRestant = cvgrp.Key.TotalAmount - cvgrp.Sum(x => x.b.Amount),
MontantCréance = cvgrp.Sum(x => x.b.IsPaid == "False" ? x.b.Amount : 0.0 )
}
It seems working but I really don't understand clearly what I did especially in the group by clause. If I add an into clause after the joins before the group by the identifier will work as a table with all the tables joined ?.
I need some explanation to understand linq more.
Thank you in advance.
using the northwind DB, i have to make a query to get employeename, amount of orders per employee and average price of those orders
this is what the query looks like in SQL
SELECT TOP 10
a.LastName, a.FirstName, amountOfOrders = COUNT(DISTINCT b.OrderID), AveragePricePerOrder = SUM(c.Quantity*c.UnitPrice) /COUNT(DISTINCT b.OrderID)
FROM Employees a join orders b on (a.EmployeeID = b.EmployeeID)
join [Order Details] c on b.OrderID = c.OrderID
Group BY a.EmployeeID, a.LastName, a.FirstName
ORDER BY amountOfOrders Desc
this runs fine but I have to make this in c# and I am a little stuck
So far, I have got this
var query_rx = (from c in ctx.Employees
join or in ctx.Orders on c.EmployeeID equals or.EmployeeID
join ord in ctx.Order_Details on or.OrderID equals ord.OrderID
group c by new
{
c.EmployeeID,
c.LastName,
c.FirstName,
amount = c.Orders.Count
} into c
orderby c.Key.amount descending
select new
{
c.Key.LastName,
c.Key.FirstName,
amountOfOrders = c.Key.amount
}).Take(10);
"edit" I am having trouble working the average in, tried a lot of things but I can't get it to work
"edit" I have changed the query a bit with help from Dohnal's suggestion.
This looks almost exactly like what i want in terms of columns, except that the field lastname and firstname are blank, even with ToString
var query_rx = (from or in ctx.Order_Details
join ord in ctx.Orders on or.OrderID equals ord.OrderID
group or by new
{
ord.EmployeeID
} into c
orderby c.Select(x => x.OrderID).Distinct().Count() descending
select new
{
Lastname = (from emp in ctx.Employees
where c.Key.EmployeeID == emp.EmployeeID
select emp.LastName),
Firstname = (from emp in ctx.Employees
where c.Key.EmployeeID == emp.EmployeeID
select emp.FirstName),
c.Key.EmployeeID,
AmountOfOrders = c.Select(x => x.OrderID).Distinct().Count(),
AveragePricePerOrder = c.Sum(x => x.Quantity * x.UnitPrice) / c.Select(x => x.OrderID).Distinct().Count()
}).Take(10);
Try this query:
var query = (from emp in ctx.Employers
join order in ctx.Orders on emp.EmployeeID equals order.EmployerID
join orderDet in ctx.Order_Details on order.OrderID equals orderDet.OrderID
group new { emp, order, orderDet }
by new { emp.FirstName, emp.LastName, emp.EmployeeID, order.OrderID }
into orderGroup
let a = new
{
orderGroup.Key.EmployeeID,
orderGroup.Key.FirstName,
orderGroup.Key.LastName,
orderGroup.Key.OrderID,
sum1 = orderGroup.Sum(x => x.orderDet.Quantity * x.orderDet.UnitPrice),
}
group a by new { a.FirstName, a.LastName, a.EmployeeID } into empGroup
let a2 = new
{
empGroup.Key.FirstName,
empGroup.Key.LastName,
sum = empGroup.Sum(x => x.sum1),
count = empGroup.Count()
}
orderby a2.count descending
select new
{
a2.FirstName,
a2.LastName,
amountOfOrders = a2.count,
AveragePricePerOrder = a2.sum / a2.count
}).Take(10);
I have a query in entity framework which gets some messages from tables.
var ur = (from m in en.Messages
join mb in en.aspnet_Membership on m.FromUserId equals mb.UserId
join urs in en.UserProfiles on mb.UserId equals urs.UserId
join g in en.Groups on m.ToUserId equals g.GroupId
join ug in en.UserInGroups on g.GroupId equals ug.GroupId
where ug.UserId == userId
select new
{
InboxId = m.MessageId,
FromUser = urs.RaveName.Trim(),
CreatedOn = m.CreatedOn
}
).Concat(
// msg is not deleted
from m in en.Messages
join mb in en.aspnet_Membership on m.FromUserId equals mb.UserId
join urs in en.UserProfiles on mb.UserId equals urs.UserId
where m.ToUserId == userId
select new
{
InboxId = m.MessageId
,
FromUser = urs.RaveName.Trim()
,
CreatedOn = m.CreatedOn
}
);
I have another table which shows whether the message is used:
var msg = (from m in en.MessagesUsed
where m.UserId == userId
select m
);
Now, I need to check: Is there a message in 'ur' that is not in 'msg'? In T-SQL, we can use:
SELECT 1
FROM ur
WHERE NOT EXISTS (SELECT 1 FROM msg WHERE msg.Id = ur.InboxId AND msg.FromUser = ur.FromUser AND msg.CreatedOn = ur.CreatedOn)
to check this. But how to do it in LINQ?
Thanks
Here is my working LINQ to dataset query. I have added a fourth table and I want to add a NOT IN type filter to the query where query1.dedpk NOT IN deduct.dedpk. Not sure how to do it.
var main = dsTemp.Tables["Maindata"].AsEnumerable();
var pg = dsTemp.Tables["pgto"].AsEnumerable();
var py = dsTemp.Tables["pyto"].AsEnumerable();
var deduct = dsTemp.Tables["Deduct"].AsEnumerable();
var query1 = from mainrow in main
join pgrow in pg on mainrow.Field<string>("pgpk") equals pgrow.Field<string>("pgpk")
join pyrow in py on mainrow.Field<string>("pypk") equals pyrow.Field<string>("pypk")
into griddata
select new
{
lastname = mainrow.Field<string>("lastname"),
firstname = mainrow.Field<string>("firstname"),
dedpk = mainrow.Field<string>("dedpk"),
};
Thanks
var query1 = from mainrow in main
join pgrow in pg on mainrow.Field<string>("pgpk") equals pgrow.Field<string>("pgpk")
join pyrow in py on mainrow.Field<string>("pypk") equals pyrow.Field<string>("pypk")
into griddata
where
!deduct.Any(x => x.Field<string>("dedpk") == mainrow.Field<string>("dedpk"))
select new
{
lastname = mainrow.Field<string>("lastname"),
firstname = mainrow.Field<string>("firstname"),
dedpk = mainrow.Field<string>("dedpk"),
};