Finding a TOP LEVEL parent in Entity Framework Query - c#

I have got two tables as following
Table Person
Id Name
1 A
2 B
3 C
4 D
5 E
Table RelationHierarchy
ParentId CHildId
2 1
3 2
4 3
This will form a tree like structure
D
|
C
|
B
|
A
ParentId and ChildId are foreign keys of Id column of Person Table
Let's suppose to EF entity Names are as Table names. I need to find top level Parent of Each person. Resultset should be as following
PersonId PersonName TopLevelPArentID TopLevelPArentName
Can anyone suggest any LINQ or LINQ to Entity Query?

The top parent would have ParentId set to NULL I assume?
Using that assumption we can go through each Person using a recursive function.
public YourMainFunction(){
List<Person> allPersons = entityContext.Person.ToList();
List<KeyValuePair<Person, Person>> personAndParents = new List<KeyValuePair<Person, Person>>();
foreach(Person p in allPersons){
personAndParents.Add(new KeyValuePair<Person, Person>(p, GetTopParent(p)));
}
}
//Now you have a list of each Persons Parents in a key/value pair list.
public Person GetTopParent(Person p){
if(p.RelationHierarchy.Count(r=>r.ParentId != null) == 0){
return p;
}
else{
return GetTopParent(p.RelationHierarchy.FirstOrDefault(r=>r.ParentId != null).Person1); //This should be the parent relation, not the child relation, im not sure what you have named the relations.
}
}

Related

Using Where clause in Group Join

Please Consider these 2 tables:
CategoryID CategoryName CategoryModel
-----------------------------------------------------------
1 Book 1
2 Shoe 2
3 Glass 1
and
SubCategoryID SubCategoryName CategoryID SubCategoryModel OtherColumn1 OtherColum2
---------------------------------------------------------------------
1 Book1 1 3
2 Book2 1 1
3 Shoe1 2 2
4 Shoe2 2 2
I want such this query:
from a in Category
join b in SubCategory
on a.CategoryID equals b.CategoryID into grpDetail
where a.CategoryModel != b.SubCategoryModel <----------
select new
{
Id = a.CategoryID,
Count1 = grpDetail.Count(o=>o.OtherColumn1 == 1),
...
}
the problem id I can't access to b in above specifies line. How can I write this query?
Thanks
There is a straightforward one to many relation between Categories and SubCategories: every Category has zero or more SubCategories; every SubCategory belongs to exactly one Category, namely the Category that the foreign key SubCategory.CategoryId refers to.
You want to join Category and SubCategory on this foreign key. You don't want all Category-SubCategory combinations that match, you want only those where Category.CategoryModel is not equal to SubCategory.SubCategoryModel.
From the remaining records, you want to select several properties. I don't see property GrpDetail in your classes, so I don't know what you want.
Luckily you mention that your problem is in the Where:
var result = Categories.Join(SubCategories, // join tables Categories and SubCategories
category => category.Id, // from every category take the Id,
subCategory => subCategory.CategoryId, // from every subCategory take foreign key CategoryId
(category, subCategory) => new // when they match make one new object
{
// we need at least Category.CategoryModel and SubCategory.SubCategoryModel
CategoryModel = category.CategoryModel,
SubCategoryModel = subCategory.SubCategoryModel,
// Select other Category properties that you plan to use:
CategoryId = category.Id,
...
// Select other SubCategory properties that you plan to use:
...
})
// we don't want all combinations, only those where
// CategoryModel is not equal to SubCategoryModel
.Where(joinResult => joinResult.CategoryModel != joinResult.SubCategoryModel)
// from the remaining combinations calculate the final result
.Select(joinResult => new
{
Id = joinResult.CategoryId,
Count1 = ... // sorry, don't know what property grpDetail does
...
});
split your query into 2, first do your join with the where clause and then do your group by.

Linq Expression to select items based on list

I have a table with parentId field and childId field.I have to select the childId field data based on a list of parentId comparing with parentId field values.
here is the sample:
List<int> parents=new list(){1,2,4};
Table :
parentId childId
1 3
5 5
2 4
4 7
how can i select the childId using linq expression
var childId = child.Where(x => parents.Contains(x.parentId)).Select(x => x.childId).ToList();
var childId = yourTable.Where(m => parents.Contains(m.parentId)).Select(m => m.childId).ToList()

Linq to recurse through a hierarchy

I have a heirarchical data structure as follows.
TABLE 1
id | Groupname | parentId
TABLE 2
id | nodeName | parentId
Table 1 parentId refers to table1 Id, and table2 parentId also refers to table 1 id.
Starting at any ID in table 1, I need to print out all the nodes, and then traverse through the children of all child groups.
Up to now I have this
int id = 1; // replace with argument
repository.Nodes.Where(n => n.ParentId == Id).ToList().ForEach(d =>
{
result.NodeList.Add(GetNodeDetails(n.Id));
});
Can anyone help me get this looping through in nice efficent linq manner?
If I understand you correctly you want to flatten the hierarchy, i.e. the end result should be one flat list with all children of all hierarchy levels.
The simplest way to achieve this is through recursion:
private IEnumerable<Node> GetSelfAndChildren(Node node)
{
yield return GetNodeDetails(n.Id);
foreach(var c in n.Children.SelectMany(GetSelfAndChildren)
yield return c;
};
var result = repository.Nodes.Where(n => n.ParentId == Id)
.AsEnumerable()
.SelectMany(GetSelfAndChildren)
.ToList();
This uses a recursive method to get a flat list of children.
This approach has the potential to exhibit the N+1 problem. Depending on the configuration each access of Children will cause a roundtrip to the database.
If the N+1 problem is happening and causing - well - problems, an alternative approach would be to first fetch all nodes from the database and then perform a Breadth-first search.

LINQ search records until parentid = 0

I have a C# List with 3 fields: ID, Name and ParentID. I am binding it to a treeview. Now I am also having a search feature where I want to filter the List and rebind the treeview.
If I search for child-1-1, my linq should be able to get following records: parent-1, child-1-1. So that I have to get records containing my search text and than get the record with ID as ParentID of this. All ParentIDs(roots) have ParentID value 0 so I have to keep on getting records until ParentID is 0.
Example of Data:
ID Name ParentID
1 parent-1 0
2 parent-2 0
3 child-1-1 1
4 child-1-2 1
5 child-2-1 2
So my question is how can I get a LINQ expression to get records like I described above?
I mean something like var mydata = from p in this.mylist where...???
assuming you have List<Node> myList where Node class with properties (Id, ParentId, ...) based on https://stackoverflow.com/a/7063002/1594178 variant for you
static IEnumerable<Node> Parents(this IEnumerable<Node> nodes, int startId)
{
Node node = nodes.Where(n => n.Id = startId).Single();
yield return node;
while (node.ParentId != 0)
{
node = nodes.Where(n => n.Id = node.ParentId).Single();
yield return node;
}
}
to populate mydata with parents of your child with id = 3 along with that child use
var mydata = mylist.Parents(3)

Recursive function to show hierarchial display using c#

I am having a table like this
ID Title Parentid
1 Level1 0
2 Level2 1
3 Level3 2
4 Level4 1
I want output in hierarchy model according to the parentid ,Id relationship as
Level1
->Level2->Level 3
-> Level4.
I am able to achieve like
level1
/\
level2 level4.
Here I am not getting level 3.
But i want the ouptut as shown in the first example using c#.
(Untested) Try:
;with RCTE as
(select id, title full_path from MyTable where ParentID = 0
union all
select m.id, r.full_path & '->' & m.title full_path
from MyTable m, RCTE r
where m.parentid = r.id)
select full_path from RCTE
Are all the parents defined before the children?
If so, you can use a Dictionary(int, List(Item)) (sorry about the parentheses, can't seem to get the angle brackets to work) where, say,
public class Item {
public int Id { get; set;}
public int ParentId { get; set;}
public string Title {get; set;}
}
IDictionary<int, List<Item>> CreateTree(IEnumerable<Item> nodeList){
var ret = new Dictionary<int, List<Item>>();
foreach (var item in items) {
if (!ret.ContainsKey(item.ParentId)) {
ret.Add(item.ParentId, new List<Item>());
}
ret[item.ParentId].Add(item);
}
return ret;
}
This will give (for the above data)
0 => level1
1 => level2, level4
2 => level3
If the parent ids are not guaranteed to be before the child ids, then you need to add in some tweaking to allow for orphans and then add then process them at the end.
Hope this helps,
Alan.
The recursion should be done inside of SQL Server using a Common Table Expression query (CTE). One query should be able to give the results and the "levels" which can then be parsed in C# without the need for recursion in code.
Here's a link with examples: (Mark's example also applies)
http://msdn.microsoft.com/en-us/library/ms186243.aspx

Categories

Resources