How to use Group By with Join and Min in Linq - c#

I have two tables.
Order:
ID
ProductID
DeliveryDate
Product:
ID
Name
Description
I want to get the list of all product with earliest delivery date.
I am getting correct data by using following sql.
This gives me list of all products with earliest delivery date.
SELECT
p.Name, p.Description, min(o.DeliveryDate)
FROM Product p
JOIN Order o
On o.ProductID = p.ID
Group By p.ID;
I have tried to write it using Linq but something is missing.
I am not able to identify how can I write this query.
I have tried out relative stack overflow solutions but not helped in my case.
My Linq is :
await (from p in dbContext.Product
join o in dbContext.Order
on o.ProductID equals p.ID
select new
{
p.ID,
p.Name,
p.Description,
o.DeliveryDate
}).GroupBy(g => g.ID).ToListAsync();
It gives me data after join and group by. Where should I put Min in the Linq to get the Earliest DeliveryDate for the Product?

I assume you have a navigation property Product.Orders. If not, it's highly recommended to add it to your code. Having that property, this will achieve what you want:
from p in dbContext.Product
select new
{
p.ID,
p.Name,
p.Description,
MinDeliveryDate = (DateTime?)o.Orders.Min(o => o.DeliveryDate)
}
The cast to DateTime? is to prevent exceptions when products don't have orders.
If for some reason you don't have the navigation property and really can't add it at the moment you can use:
from p in dbContext.Product
select new
{
p.ID,
p.Name,
p.Description,
MinDeliveryDate = (DateTime?)dbContext.Order
.Where(o => o.ProductID == p.ID)
.Min(o => o.DeliveryDate)
}
Note that by starting the query at Product and not joining with Order you don't need the grouping any more.

I used some classes to stand in for the database, but does this work?
class Product
{
public int ID;
public string Name;
public string Description;
}
class Order
{
public int ProductID;
public DateTime DeliveryDate;
}
class Program
{
static void Main(string[] args)
{
Product[] proTestData = new Product[]
{
new Product() {ID=1, Name="Widget", Description="Banded bulbous snarfblat"},
new Product() {ID=2, Name="Gadget", Description="Hitchhiker's guide to the galaxy"}
};
Order[] ordTestData = new Order[]
{
new Order() {ProductID=1, DeliveryDate=new DateTime(2017,12,14)},
new Order() {ProductID=1, DeliveryDate=new DateTime(2017,12,20)},
new Order() {ProductID=2, DeliveryDate=new DateTime(2017,12,23)},
new Order() {ProductID=2, DeliveryDate=new DateTime(2017,12,22)},
new Order() {ProductID=2, DeliveryDate=new DateTime(2017,12,21)},
new Order() {ProductID=1, DeliveryDate=new DateTime(2017,12,18)}
};
var rows =
(from p in proTestData
join o in ordTestData
on p.ID equals o.ProductID
group o.DeliveryDate by p into grp
select new {
grp.Key.ID,
grp.Key.Name,
grp.Key.Description,
minDate = grp.Min()}
).ToList();
foreach (var row in rows)
{
Console.WriteLine("{0}: {1}", row.Name, row.minDate);
}
}
}
The output is
Widget: 12/14/2017 12:00:00 AM
Gadget: 12/21/2017 12:00:00 AM

If you're trying to order your groups you can use the "OrderBy" linq method.
Apply the following after the .GroupBy()
.OrderBy(group => group.First().DeliveryDate).ToListAsync();

Related

how to apply join or innerquery to connect two table

Here MyChildTable contains only id and the parent table contains id + name.
I have written a query to fetch the existing data from the table
await _dbContext.MyChildTable
.Where(c => c.CustomerId == **(select customerid from tableParent where customername= reqcustomername)**
Here i want to match customerId with the matching customer id from the second table ie tableParent.How to replace the query in to linq to get the proper record.select customerid from tableParent where customername= reqcustomername i want to replace this selection
I don't understand what you mean
so my maybe answer error
LINQ
using (entity entityData = new entity())
{
var checkqry2 = from T1 in entityData.MyChildTable.AsNoTracking()
join T2 in entityData.tableParent on
T1.CustomerId equals T2.customerid
where T1.customerid == "ID" && T2.customername == reqcustomername
group new { T2.customerid, T2.customername } by new { T1.customerid, T1.customername } into c
orderby c.Key.customerid
select new { customername=c.Key.customername,
customerid=c.Key.customerid,
};
}
you can try entity lambda
entity lambda
using (entity entityData = new entity())
{
var query1 = entityData.MyChildTable
.Join(entityData.tableParent , o => o.CustomerId , p => p.CustomerId , (o, p) => new
{
o.CustomerId,
p.customername,
}).Where(o => o.CustomerId == "123" && o.customername == "name").ToList();
}
Here I want to match customerId with the matching customer id from the
second table ie tableParent.How to replace the query in to linq to get
the proper record.select customerid from tableParent where
customername= reqcustomername i want to replace this selection
Well, lot of way around to handle this kind of scenario. Most easy and convenient way you could consider by using linq join or linq Enumerable which you can implement as following:
Sample Data:
var childList = new List<ChildTable>()
{
new ChildTable(){ Id =101,ChildName = "Child-A",CustomerId = 202},
new ChildTable(){ Id =102,ChildName = "Child-B",CustomerId = 203},
new ChildTable(){ Id =103,ChildName = "Child-C",CustomerId = 202},
new ChildTable(){ Id =104,ChildName = "Child-D",CustomerId = 204},
};
var parentList = new List<ParentTable>()
{
new ParentTable(){ Id =301,ParentName = "Parent-A",CustomerId = 202},
new ParentTable(){ Id =302,ParentName = "Parent-B",CustomerId = 202},
new ParentTable(){ Id =303,ParentName = "Parent-C",CustomerId = 203},
new ParentTable(){ Id =304,ParentName = "Parent-D",CustomerId = 205},
};
Linq Query:
Way One:
var findMatchedByCustId = from child in childList
where (from parent in parentList select parent.CustomerId)
.Contains(child.CustomerId)
select child;
Way Two:
var usingLinqJoin = (from parent in parentList
join child in childList on parent.CustomerId equals child.CustomerId
select parent).ToList().Distinct();
Output:
Note: If you need more information you could check our official document for Linq join and Linq Projction here.

GridView Only populating 1 result

I'm currently working to add Data to a GridView. The data comes from 2 tables that are on different databases. Currently I am able to populate the first entry, but it does not populate past that. here is the code:
void FillOrder(int inv)
{
var _ord = new OrdersContext();
var _pro = new ProductContext();
var qryOrder = (from o in _ord.OrderDetails
where o.InvNumberId == inv
select new
{
o.ProductID,
o.Quantity
}).ToList();
foreach (var order in qryOrder)
{
int prodID = order.ProductID;
int itemCount = qryOrder.Count;
var qryProducts = (from p in _pro.Products
where p.ProductID == prodID
select new
{
p.ProductID,
p.ProductName
}).ToList();
var results = (from t in qryOrder
join s in qryProducts
on t.ProductID equals prodID
select new
{
t.ProductID,
t.Quantity,
s.ProductName
}).ToList();
OrderItemList.DataSource = results;
OrderItemList.DataBind();
}
}
Can anyone help as to why it's only populating the first entry?
If the number of products involved is relatively small, (and since this query seems to be relate to one invoice, I would think that is true), then you can probably use something like the code below.
This is removing the loop, but the contains method will probably generate a SQL statement something like select ProductID, ProductName from products where productID in (,,,,,,) so may fail if the number of parameters is extremely large.
var _ord = new OrdersContext();
var _pro = new ProductContext();
var qryOrder = (from o in _ord.OrderDetails
where o.InvNumberId == inv
select new
{
o.ProductID,
o.Quantity
}).ToList();
// Get the productIDs
var productIDS = qryOrder.Select(o=>o.ProductID).Distinct().ToList();
// Get the details of the products used.
var qryProducts = (from p in _pro.Products
where productIDS.Contains(p.ProductID)
select new
{
p.ProductID,
p.ProductName
}).ToList();
// Combine the two in memory lists
var results = (from t in qryOrder
join s in qryProducts
on t.ProductID equals s.ProductID
select new
{
t.ProductID,
t.Quantity,
s.ProductName
}).ToList();
OrderItemList.DataSource = results;
OrderItemList.DataBind();

Creating table which changes a column in order to remove repeated values in rows

Sorry if the title was confusing.
Currently I am practicing with Entity Framework and LINQ expressions and got stuck on this.
I have a table with columns:"Personal ID", "Name", "Surname", "Phone ID" and all values on Phone ID are unique. I would like to create another table in which there would be same columns except for last being "Phone Count" which shows how many phones are associated with same Person(Personal ID). I want the table to show only 3 first highest count rows.
Here is the code i've wrote to make table that i've described above.
using (var db = new PRDatabaseEntities())
{
var query = from a in db.Person
join t in db.Repairs on a.PID equals t.Repairman_PID
orderby a.PID
select new
{
a.PID,
a.Name,
a.Surname,
t.Phone_ID
};
}
You could try with following group by LINQ query:
// First, generate a linq query
var query = from a in Persons
join t in Repairs on a.PID equals t.Repairman_PID
group new { a, t } by new { a.PID, a.Name, a.Surname } into g
select new
{
PID = g.Key.PID,
Name = g.Key.Name,
Surname = g.Key.Surname,
PhoneCount = g.Count()
};
// Then order by PhoneCount descending and take top 3 items
var list = query.OrderByDescending(t => t.PhoneCount).Take(3).ToList();
Try this:
using (var db = new PRDatabaseEntities())
{
var query = db.Person
.GroupJoin(db.Repairs,
p => p.PID, r => r.PID,
(p, r) => new {
PID = p.PID,
Name = p.Name,
Surname = p.Surname,
Count = r.Count()
};
}

Applying orderby to C# LINQ Inner join

I am trying out C# LINQ Joins from this msdn page.
I am not able to apply order by on inner join even though it works with group join.
The data on which queries are run are:
class Product
{
public string Name { get; set; }
public int CategoryID { get; set; }
}
class Category
{
public string Name { get; set; }
public int ID { get; set; }
}
// Specify the first data source.
static List<Category> categories = new List<Category>()
{
new Category(){Name="Beverages", ID=001},
new Category(){ Name="Condiments", ID=002},
new Category(){ Name="Vegetables", ID=003},
new Category() { Name="Grains", ID=004},
new Category() { Name="Fruit", ID=005}
};
// Specify the second data source.
static List<Product> products = new List<Product>()
{
new Product{Name="Cola", CategoryID=001},
new Product{Name="Tea", CategoryID=001},
new Product{Name="Mustard", CategoryID=002},
new Product{Name="Pickles", CategoryID=002},
new Product{Name="Carrots", CategoryID=003},
new Product{Name="Bok Choy", CategoryID=003},
new Product{Name="Peaches", CategoryID=005},
new Product{Name="Melons", CategoryID=005},
};
The desired output is (list order by categories in brackets and then by product) :
Cola(Beverages)
Tea(Beverages)
Mustard(Condiments)
Pickles(Condiments)
Melons(Fruit)
Peaches(Fruit)
Bok Choy(Vegetables)
Carrots(Vegetables)
I was able to produce this output using group-join with orderby and 2nd from-select to deform group hierarchy and produce plain list as follows:
var listGroupJoinOrderBy =
from category in categories
join product in products on category.ID equals product.CategoryID into prodGroup
from prod in prodGroup
orderby category.Name, prod.Name //first order by category name then product name
select
new
{
Category = category.Name,
Product = prod.Name
};
But then I am unable to produce this same output with orderby applied to inner join (that is group-join without into clause). I tried following variants:
Variant #1
var innerJoinOrderBy =
from category in categories
orderby category.Name //orderby category name
join product in products on category.ID equals product.CategoryID
orderby product.Name //orderby product name
select
new
{
Category = category.Name,
Product = product.Name
};
Variant #2
var innerJoinOrderBy =
from category in categories
join product in products on category.ID equals product.CategoryID
orderby category.Name, product.Name //orderby category first and then by product name
select
new
{
Category = category.Name,
Product = product.Name
};
However both variants give the same output as if no orderby is used, and produces the following output:
Cola (Beverages)
Tea (Beverages)
Mustard (Condiments)
Pickles (Condiments)
Carrots (Vegetables)
Bok Choy (Vegetables)
Peaches (Fruit)
Melons (Fruit)
Q. How can I produce the desired output with inner-join and orderby?
Anyway, to print the query result one can use following foreach (just change the query variable name) :
foreach (var product in simpleInnerJoin)
{
Console.WriteLine(product.Product + " (" + product.Category + ")");
}
Your second option should work fine
var innerJoinOrderBy =
from c in categories
join p in products on c.ID equals p.CategoryID
orderby c.Name, p.Name
select new {
Category = c.Name,
Product = p.Name
};
Output:
[
{ Product="Cola", Category="Beverages" },
{ Product="Tea", Category="Beverages" },
{ Product="Mustard", Category="Condiments" },
{ Product="Pickles", Category="Condiments" },
{ Product="Melons", Category="Fruit" },
{ Product="Peaches", Category="Fruit" },
{ Product="Bok Choy", Category="Vegetables" },
{ Product="Carrots", Category="Vegetables" }
]
From your output I see that items go in their original order. Make sure you have applied orderby operator in query.
Take the Orderby out of the main Linq and use
foreach (var product in simpleInnerJoin.Orderby(i=> i.Category.Name).ThenBy(i=>i.Product.Name))
{
Console.WriteLine(product.Product + " (" + product.Category + ")");
}
I think this should give you the output you require.

Select a field that is not in Group By clause in LINQ

could anybody help me about
"How to select a field that is not in Group By clause in LINQ"
var ReportData =
from a in context.Table1
from b in context.Table2
where a.personelID == b.ID
&& a.DateField.Value.Year == 2011
group a by new { a.personelID, b.Name, b.Surname} into grouping
select new
{
// grouping.Key.DateField,
Name= grouping.Key.Name,
Surname= grouping.Key.Surname,
PagaBruto = grouping.Sum(i => i.Bruto)),
};
I can't select the field "DateField" that is in Table1, I don't want to have this field in Group By, because I will get a wrong result.
THANKS!
I think you need to select both table members before you group by so you can select data from both. I did a join instead of your where clause.
(from a in context.Table1
join b in context.Table2 on a.PersonalID equals b.ID
select new { A=a, B=b } into joined
group joined by new { joined.A.PersonalID, joined.B.Name, joined.B.Surname } into grouped
select grouped.Select(g => new {
DateField= g.A.Datefield,
Name = g.B.Name,
Surname = g.B.Surname,
PagaBruto = g.A.Sum(i => i.Bruto)
})).SelectMany(g => g);
Maybe this will work?
group a by new { a.personelID, b.Name, b.Surname, a.DateField} into grouping
select new
{
DateField = grouping.Key.DateField,
Name= grouping.Key.Name,
Surname= grouping.Key.Surname,
PagaBruto = grouping.Sum(i => i.Bruto)),
};

Categories

Resources