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)
Related
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()
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.
}
}
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.
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
I have a self referential table, which has ID, ParentID (nullable).
So, the table contains many nodes, each node could be the root in the hierarchy (parent is null), or any level of the hierarchy (parent exists elsewhere in the table).
Given an arbitrary starting node, is there an elegant linq query that will return all children of the hierarchy from that node?
Thanks.
If you want to select all direct children of a node, a simple query like the following should do the job:
from item in table
where item.ID == parentID;
select item
If you want to select all descendants of a node, this is not possible with LINQ, because it requires recursion or a stack which LINQ (and SQL) doesn't provide.
See also:
StackOverflow: LINQ to SQL for self-referencing tables?
CodeProject: T-SQL - How to get all descendants of a given element in a hierarchical table
StackOverflow: Expressing recursion in LINQ
Here is a quick one I just wrote:
class MyTable
{
public int Id { get; set; }
public int? ParentId { get; set; }
public MyTable(int id, int? parentId) { this.Id = id; this.ParentId = parentId; }
}
List<MyTable> allTables = new List<MyTable> {
new MyTable(0, null),
new MyTable(1, 0),
new MyTable(2, 1)
};
Func<int, IEnumerable<MyTable>> f = null;
f = (id) =>
{
IEnumerable<MyTable> table = allTables.Where(t => t.Id == id);
if (allTables
.Where(t => t.ParentId.HasValue && t.ParentId.Value == table
.First().Id).Count() != 0)
return table
.Union(f(
allTables.Where(t => t.ParentId.HasValue && t.ParentId.Value == table
.First().Id).First().Id));
else return table;
};
But I believe it is possible to do using SQL with a Union ALL.
I know this is an old post but you should check out this extension:
http://www.scip.be/index.php?Page=ArticlesNET23
I've been using it and it is working great.
Basically I'm going with something like this as discussed in the SO link you proivded.
public IQueryable GetCategories(Category parent)
{
var cats = (parent.Categories);
foreach (Category c in cats )
{
cats = cats .Concat(GetCategories(c));
}
return a;
}
CTEs are probably the best solution but I'd like to keep things all in the same tier for now.