I have two tables Customers and Orders. I want a LINQ query to fetch list of all the orders placed by all the customers organized first by month and then by year. If there is no order corresponding to the customer, "No Orders” should be displayed.
The columns of Customers table are
customer_id
name
city
The columns of Orders table are
order_id
order_date
order_total
customer_id
I tried writing it the following way but its not giving complete output.
var res = from cust in db.Customers
join ord in db.Orders
on cust.customer_id equals ord.customer_id into g
from d in g.DefaultIfEmpty()
select new {
name=cust.name,
oId=d.order_id==null?-1:d.order_id
};
How do I rectify it?
I finally got the right answer which exactly the result as expected. I have put it below. I have used two LINQ queries to arrive at the result though. The first one gives the result, but the final result needs to be displayed with names of customer and their order totals, hence it is partial result. The second LINQ query further refines the 'partialResult' and gives the result as expected.
var partialResult = (from c in db.Customers
join o in db.Orders
on c.customer_id equals o.customer_id
select new
{c.name,
o.order_total,
o.order_date }).OrderBy(m => m.order_date.Month).ThenBy(y => y.order_date.Year);
var finalResult = from c in db.Customers
orderby c.name
select new
{
name = c.name,
list = (from r in partialResult where c.name == r.name select r.order_total).ToList()
};
foreach (var item in finalResult)
{
Console.WriteLine(item.name);
if (item.list.Count == 0)
{
Console.WriteLine("No orders");
}
else
{
foreach (var i in item.list)
{
Console.WriteLine(i);
}
}
}
Something like this. You can do it using LINQ Predicates
var res = Customers.Join(Orders, x => x.customer_id, y => y.customer_id, (x, y) => x).ToList();
This is what you can do:
var res = from cust in db.Customers
join ord in db.Orders
on cust.customer_id equals ord.customer_id into g
from d in g.DefaultIfEmpty()
orderby d.OrderDate.Year, d.OrderDate.Month
select new {
name=cust.name,
oId = d.order_id.ToString() ?? "No Orders"
};
Related
I have a Linq to SQL query that I want to return select columns from all matching rows from one table (TableC in my simplified query below) and a count of matching rows in another table (TableB in below). Certain other tables need to be involved too for the where clause to work (removed in simplified query).
How do I get the columns I need from TableC and a count of TableB?
This is a simplified version of my query:
var q = from a in dc.TableA
from b in dc.TableB
join c in dc.TableC on b.TableBID equals c.ID
join d in dc.TableD on a.ID equals d.TableAID
where 1 == 1 //lots of interesting stuff here
group c by new { b, c } into g
select new
{
ID = g.Key.c.ID,
Name = g.Key.c.Name,
Count = g.Count()
};
Update: I think I found a solution using group joins - answer posted below. I would still like to know if that was the right solution.
I came up with this solution after reading about Linq group joins.
var q = from a in TableC
join b in (from c in TableB
where (from d in TableA
join f in TableD on d.ID equals f.ID
where 1 == 1 //for simplicity
select d).Any()
&& 1 == 1 //more simplification
select c) on a.TableBID equals b.ID into g
where 1 == 1 //more simplification
select new
{
a.ID,
a.Name,
Count = g.Count()
};
I've working on this for a while so I thought I'd post here to see if anyone has any idea how a query like the following can be converted to LINQ.
Here is the MySQL Query:
SELECT SUM(line_ord.itemqty) AS LineOrderQTY, SUM(assemblyNumber.qty) AS
AssemblyQTY FROM line_ord
LEFT JOIN
(
SELECT sum(assemblyno.qty) AS qty, assemblyno.row_id FROM assemblyno
INNER JOIN line_ord ON assemblyno.row_id = line_ord.row_id
WHERE line_ord.bdnum = 'S61460'
) AS assemblyNumber ON line_ord.row_id = assemblyNumber.row_id
WHERE line_ord.bdnum = 'S61460'
This what I have so far for the LINQ query, but it doesn't return the proper results.
var items = (from c in Context.OrderLineItemData
join e in Context.AssemblyLabelData on c.ID equals e.RowID
where c.BreakdownNumber == breakdownNumber
group c by c.BreakdownNumber into g
select new
{
AssemblyQuantity= g.Sum(x => x.Quantity),
LineOrdQuantity = g.Sum(**WHAT GOES HERE?**)
}).FirstOrDefault()
I did manage to get it to work like this, but it seems kind of messy to me.
var items = (from c in Context.OrderLineItemData
join e in Context.AssemblyLabelData on c.ID equals e.RowID
where c.BreakdownNumber == breakdownNumber
group c by c into g
select new
{
AssemblyQuantity= g.Sum(x => x.Quantity),
LineOrdQuantity = (from e in Context.OrderLineItemData where e.BreakdownNumber == breakdownNumber select e.Quantity).Sum()
}).FirstOrDefault();
Is there a better way to do this?
Got my answer. Seems like a query object has to be created and then I can use it to preform my calculations.
var items = (from od in Context.OrderLineItemData
join ad in Context.AssemblyLabelData on od.ID equals ad.RowID into odGroup
from g in odGroup.DefaultIfEmpty()
where od.BreakdownNumber == breakdownNumber
group g by new
{
breakdown = od.BreakdownNumber,
LineOrd = od,
AssemblyQty = g == null ? 0 : g.Quantity
}
into groupped
select new
{
Breakdown = groupped.Key.breakdown,
AssemblyQty = groupped.Sum(x => x.Quantity),
lineOrdQty = groupped.Key.LineOrd.Quantity
}
);
int remainingQuantity = items.Sum(x => x.lineOrdQty) - items.Sum(x => x.AssemblyQty);
Can anyone help me with the equivalent LINQ query for the SQL below?
I am new to LINQ
Select * From Students_History SH
Where SH.Active = 1 and SH.ModifiedAt in (
select MAX(SH1.ModifiedAt)from Students_History SH1
group by SH1.StudentId)
This is what I have tried
var q =
from h in Students_History
where h.Active=1
group h by h.StudentId into g
select new
{
StudentID = g.Key,
LatestModified = g.Max (x => x.ModifiedAt)
}
This linq query does not give me the right result and somehow the active=1 is ignored
I have about dozen fields in my Students_History table and I want all those fields not just studentId and ModifiedAt.
Try this:
var q =
from hg in Students_History
group hg by hg.StudentId into g
join h in Students_History on g.Key equals h.StudentId
where h.Active == 1 && h.ModifiedAt == g.Max(x => x.ModifiedAt)
select new
{
StudentID = h.StudentId,
LatestModified = h.ModifiedAt
}
You need to compare using the == operator.
I want to group results of query by the item id and count number of items in each group. finally i will take only one item from each group and the count of that group to display
results.GroupBy(r=>r.ID)....
You can do some grouping in Linq like this:
var items = from r in rows
group r by r.ID into g
select new { Count = g.Count(), First = g.First() };
... but that'll give you a collection of objects with a "Count" property (int) and a "First" property (of the same type as your rows).
What you might want to do is select something that's shaped similarly to your row, except with a count property. One way to do that is field by field like this:
var items = from r in rows
group r by r.ID into g
let f = g.First()
select new
{
f.ID, f.Name, f.Foo, f.Bar, // etc
Count = g.Count()
};
I dont seem to be able to find any evidence of multiple groupby being supported in LinqToSQl on the internet (I should probably buy a book :))
I'd like to be able to do this:
var qry = from s in DBContext.Styles
join artist in DBContext.Artists on s.ID equals artist.StyleID
join track in DBContext.Tracks on s.ID equals track.StyleID
group artist by new { s.ID, s.Name } into a
group track by new { s.ID, s.Name } into t
select new DTO.StyleSummary
{
ID = a.Key.ID,
Name = a.Key.Name,
NumberOfArtists = a.Count(),
NumberOfTracks = t.Count()
};
However the 2nd group statement prevents compilation.. Since this is possible in native sql how can I do this??
Thoughts? Is this even possible?
Its because you don't really even need a groupby in this LINQ statement. You can just do
var qry = from s in DBContext.Styles
join artist in DBContext.Artists on s.ID equals artist.StyleID into a
join track in DBContext.Tracks on s.ID equals track.StyleID into t
select new DTO.StyleSummary
{
ID = s.ID,
Name = s.Name,
NumberOfArtists = a.Count(),
NumberOfTracks = t.Count()
};
Note the into