Reputation: 101
I have a list of objects within a list of objects (List-ParentClass) that has as one of its objects a nested list (List-ChildClass). To populate List-ChildClass I have used a foreach loop as shown below. I have also nested a linq query as show below.
At this point I am having some performance issues and I feel like there is a better way to do this that I am just not finding.
Question: How could I do this better/faster?
Note - This is a Web based .net MVC application written in C#. I use EF back to a SQL database.
public class ParentClass
{
public int pcid { get; set; }
public List<ChildClass> ChildClassList { get; set; }
}
public class ChildClass
{
public int pcid { get; set; }
public int ccid { get; set; }
}
public class DoWork
{
public void ExampleMethodForEach()
{
List<ParentClass> ParentClassList = new List<ParentClass>();
foreach(ParentClass a in ParentClassList)
{
a.ChildClassList = EFDatabase2.where(b => b.pcid == a.pcid).select(b => b.ccid).ToList();
}
}
public void ExampleMethodLinq()
{
var ParentClassList = (from a in EFDatabase
select new ParentClass
{
ccid = a.ccid,
pcid = (from b in EFDatabase2
where b.pcid == a.pcid
select b.ccid).ToList()
//something like this were I nest a query
}).ToList();
}
}
Upvotes: 6
Views: 2049
Reputation: 205539
The best way when working with relational databases and LINQ is to use joins to correlate data. In your case, the most appropriate is group join:
var ParentClassList =
(from p in EFDatabase
join c in EFDatabase2 on p.pcid equals c.pcid into children
select new ParentClass
{
pcid = p.pcid,
ChildClassList =
(from c in children
select new ChildClass
{
pcid = c.pcid,
ccid = c.ccid
}).ToList()
}).ToList();
which should give you a nice fast single database query.
P.S. Hope your EFDatabase
and EFDatabase2
variables refer to two tables inside one and the same database.
Upvotes: 2
Reputation: 23083
You are hitting your database multiple times. You have a N+1 issue.
What I suggest is to query all parents first, but excluding the children data. Then get the ID of all parents that you retrieved and put it inside an array. We will use that array to create a IN clause in SQL.
After loading all the children using the array of parent IDs, map them to a Lookup using ToLookup
using the parent ID as the key and use a foreach to assign the list of children to the parent.
var parents = EFDatabase2.Parents.Where(...).Select(p => new ParentClass { pcid = p.pcid }).ToList();
var ids = parents.Select(p => p.pcid).ToArray();
var children = EFDatabase2.Children.Where(c => ids.Contains(c.ccid)).Select(c => new ChildClass { pcid = c.pcid, ccid = c.ccid }).ToLookup(c => c.pcid);
foreach (var parent in parents)
{
parent.Children = children[parent.pcid];
}
In this case, you will only do two queries to your database.
Upvotes: 0