linq: grandparent - parent - children query - linq

I have an entity model and I've been looking to write a linq query that returns counts of children and parents for each grandparent.
I need to output 3 columns: Name of Grandparent | Count of Children | Count of Grandchildren
protected void Page_Load(object sender, EventArgs e)
{
using (FamilyModel.TheConn myEntities = new FamilyModel.TheConn())
{
int TheUserID = 13; // will change later
var myOutput = from gparents in myEntities.GrandParents
where gparents.UserID == TheUserID
select gparent.Name, // here's what's missing: the counts
GridView1.DataSource = myOutput;
GridView1.DataBind();
}
}
I've been struggling with SelectMany, Groupby, joins.... I just don't get the result I need for this seemingly simple query.
Any input would be greatly appreciated.
Thanks

var myOutput = from gparent in myEntities.GrandParents
where gparent.UserID == TheUserID
select new GrandParentViewModel
{
Name = gparent.Name,
ChildrenCount = gparent.Children.Count(),
GrandChildrenCount = gparent.Children.SelectMany(c => c.GrandChildren).Count()
};
That's assuming your Child entity has navigational property GrandChildren (actually the name Children world make more sense here - children of children = grandchildren).
In this case we project onto a GrandParentViewModel:
public class GrandParentViewModel
{
public string Name { get; set; }
public int ChildrenCount { get; set; }
public int GrandChildrenCount { get; set; }
}

Related

Linq query to select any in list against a list

Using EF Core code-first, and I want to find any record with a similar list of a foreign entities to the entity I already have.
public class ClownModel {
public int Id { get; set; }
public List<CarModel> Cars { get; set; }
}
public class CarModel {
public int Id { get; set; }
}
var MyClown = new ClownModel() { /*add properties*/ }
//or maybe an existing record selected from database, just some ClownModel instance
Basically, "Select all the ClownModels where they have any Cars.Id that are in my MyClown.Cars"
Assuming that ClownModel has unique CarModel Id's, you can use the following query:
Matches All Ids
var ids = MyClown.Cars.Select(c => c.Id).ToList();
var query =
from cm in ctx.ClownModel
where cm.Cars.Where(c => ids.Contains(c.Id)).Count() == ids.Count
select cm;
Matches Any Ids
var ids = MyClown.Cars.Select(c => c.Id).ToList();
var query =
from cm in ctx.ClownModel
where cm.Cars.Where(c => ids.Contains(c.Id)).Any()
select cm;

LINQ Lazy load or query incorrect

LINQ Query not populating
Model extract is as follows
public class ServiceBulletin
{
[Key]
public int Id { get; set; }
public virtual ICollection<ServiceBulletinProducts> ApplicableProducts { get; set; }
}
public class ServiceBulletinProducts
{
[Key]
public int Id { get; set; }
public int ServiceBulletinId { get; set; }
public virtual Product Product{ get; set; }
}
I'm using the following code at the moment to populate a collection
var x = from m in _dc.ServiceBulletins.Include(p => p.ApplicableProducts)
.Include(m => m.Manufacturer)
where m.DeleteStatus == DeleteStatus.Active
select m;
var x1 = new List<ServiceBulletin>();
foreach (var item in x)
{
var p = from m1 in _dc.ServiceBulletinsProducts.Include(p2=>p2.Product)
where m1.Product.DeleteStatus == DeleteStatus.Active &&
m1.ServiceBulletinId == item.Id
select m1;
var p99 = p.ToList();
item.ApplicableProducts = p99;
x1.Add(item);
};
So this is intended to have a Parent Child relationship and I’m trying to do a query which populates a collection of ServiceBulletins with a ApplicableProducts item with a fully populated collection of ServiceBulletinProducts for the ServiceBulletin with the values of the Product populated
The collection is populated but the ServiceBulletinProducts are always set to null and I can’t seem to add an Include such as .Include(p => p.ApplicableProducts.Products) to try and populate the product details – which is resulting in me iterating around the collection to populate the items.
Am I missing something to enable the population on the 1st query for the Include statement or do I need to do the query in a different way ?
Figured out the following should do the trick.
var x = from m in _dc.ServiceBulletins.Include(p => p.ApplicableProducts.Select(p2=>p2.Product))
.Include(m => m.Manufacturer)
where m.DeleteStatus == DeleteStatus.Active
select m;

Combine Parent and Child Lists into a single nested Parent List

I have two lists, a parent list (parents) and a child list (children) with the child list having a parentId.
List<Parent> parents
List<Child> children
I am trying to combine the two lists into a single list of parents with each parent object having a list of children. I'm currently looping through the parent list and populating the Children list within each parent object based on the parentId but I was wondering if there was a faster way to do this using LINQ.
foreach (var parent in parents)
{
parent.Children = children.Where(c=>c.ParentId == parent.Id).ToList();
}
Any suggestions?
You can use a Join, combined with a GroupBy:
var parentChildrenQry =
from parent in parents
join child in children on parent.Id equals child.ParentId
group child by parent;
foreach(var grp in parentChildrenQry) {
grp.Key.Children = grp.ToList();
}
Or both in one statement with GroupJoin:
var parentChildrenQry =
parents.GroupJoin(children, parent.Id, child.ParentId, new { (parent, childGrp) => new { Parent = parent, Children = childGrp.ToList() } );
foreach(var grp in parentChildrenQry) {
grp.Parent.Children = grp.Children;
}
From a performance point of view there is nothing wrong with your foreach.
If your code is readable enough there is no point to make your code linq and fancy.
If your collections are very large, from performance perspective it might be most efficient if you firstly group your children by parent id and sort groups by parent id and get them appended to the sorted parents.
I know it is an old question but I'd like to share my experience
for me I have a lot of records in database so the performance is important I crate it in another way and get the result about 3 times faster. I get all data in one select then put results in my models.
I have restaurant database with menus and dishes tables.
At first these are the classes models that will handle the selected data and are different from database models
public class Menu
{
public Menu()
{
Dishes = new List<Dish>();
}
public long ID { get; set; }
public string Name { get; set; }
public string ImagePath { get; set; }
public List<Dish> Dishes { get; set; }
}
public class Dish
{
public long ID { get; set; }
public string Name { get; set; }
public string PicturePath { get; set; }
public double Price { get; set; }
}
This is the Linq query
var all = (from m in contexts.RestMenus
join d in contexts.ResDishes on m.Id equals d.MenuID
select new
{
Menu = new Menu()
{
ID = m.MenuID,
Name = m.Name,
ImagePath = m.ImageURL
},
Dish = new Dish()
{
ID = d.ItemID,
Name = d.Name,
PicturePath = d.PicturePath,
Price = d.DefaultPrice
}
}).ToList();
and the foreach loop to arrange the data
List<Menu> menus = new List<Menu>();
foreach (var r in all)
{
Menu m = menus.Find(x => x == r.Menu);
if (m == null)
{
menus.Add(r.Menu);
m = r.Menu;
}
m.Dishes.Add(r.Dish);
}

WP: How to use ToList() method for select multiple columns statement in linq to sql?

I selected 4 columns from my table by using select statement LINQ to SQL. Then I create a new List to store the query result. BUT, the code room.ToList(); is WRONG.
Why cannot we use "rooms_list = room.ToList()"?
How should we do to solve the problem???
Thanks for teaching me!
private void btnTest_Click(object sender, EventArgs e)
{
List<string> rooms_list = new List<string>();
using (LVDatabaseEntities database = new LVDatabaseEntities())
{
var room = from x in database.PHONGCHOIs
select new { x.TENPHONG, x.MATKHAUPHONG, x.CHUPHONG, x.SOLUONG };
rooms_list = room.ToList();
}
MessageBox.Show(rooms_list.Count.ToString());
}
Your rooms_list = room.ToList() is wrong, because it is not the List of type string.
To fix this, first create a class for a room
class Room
{
string TENPHONG { get; set; }
string MATKHAUPHONG { get; set; }
string CHUPHONG{ get; set; }
string SOLUONG{ get; set; }
}
Then, change your code like this
List<Room> rooms_list = new List<Room>();
using (LVDatabaseEntities database = new LVDatabaseEntities())
{
var rooms = from x in database.PHONGCHOIs
select new Room{
TENPHONG = x.TENPHONG,
MATKHAUPHONG = x.MATKHAUPHONG,
CHUPHONG = x.CHUPHONG,
SOLUONG = x.SOLUONG };
rooms_list = room.ToList();
}
MessageBox.Show(rooms_list.Count.ToString());
*Not tested. Let me know if anything didn't work

linq count/groupby not working

I want to group by the categoryid and then do a count on this. But I don't know how to do this. I have tried a couple of ways without success. Here is my latest:
public class Count
{
public int TradersCount { get; set; }
public int Id { get; set; }
public string Description { get; set; }
}
public IQueryable<Count> CountTradersAttachedToCategories()
{
var data = from tc in _db.tblTradersCategories
select new Count
{
Description = tc.tblCategory.description,
Id = tc.tblCategory.categoryId,
TradersCount = tc.Select(x => x.categoryid).GroupBy().Count()
};
return data;
}
tblTradersCategories joins both
tblTraders/tblCategories
A single trader can have many categories
A single category can have many traders
Thanks in advance for any help.
Clare
Try this:
var data = from tc in _db.tblTradersCategories
group tc by new { tc.tblCategory.categoryId,
tc.tblCategory.description } into g
select new { Count = g.Count(),
Id = g.Key.categoryId,
Description = g.Key.description };
If you want that in your Count class you may need to use AsEnumerable() to perform the conversion in process:
var converted = data.AsEnumerable()
.Select(c => new Count { TradersCount = c.Count,
Id = c.Id,
Description = c.Description });
You can try doing them all in one go:
var data = from tc in _db.tblTradersCategories
group tc by new { tc.tblCategory.categoryId,
tc.tblCategory.description } into g
select new Count { TradersCount = g.Count,()
Id = g.Key.categoryId,
Description = g.Key.description };
But I don't know if that will work. It depends on how the LINQ provider handles it.

Resources