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
Related
In oracle I can do the following query:
SELECT *
FROM Tabl Tabb
WHERE (tabb.Col1, tabb.Col2) IN ( (1,2), (3,4))
Consider I 've following entity:
public class Tabb
{
public int Col1 {get; set; }
public int Col2 {get; set; }
// other props
}
and criteria class
public class Search
{
public int Col1 {get; set; }
public int Col2 {get; set; }
}
I need to write:
public IEnumerable<Tabb> Select(IEnumerable<Search> s)
{
var queryable = this.context.Tabbs;
return queryable.Where(\* some *\).ToList();
}
How can I select entities, that search collection contain instance of search that has the same value of Col1 and Col2?
EDIT:
var result = from x in entity
join y in entity2
on new { x.field1, x.field2 } equals new { y.field1, y.field2 }
It doesn't work (As I expected) - in may case entity2 is not a entity table, it is static collection, so EF throws exception (sth like: cannot find mapping layer to type Search[]);
There's a few ways, which all have pros and cons, and are sometimes a little bit tricky...
Solution 1
You enumerate the ef part first (of course, depending on the size of your data, this might be a very bad idea)
Solution 2
You concatenate your fields with an element you're sure (hum) you won't find in your fields, and use a Contains on concatenated EF data.
var joinedCollection =entity2.Select(m => m.field1 + "~" + m.field2);
var result = entity.Where(m => joinedCollection.Contains(m.field1 + "~" + m.field2));
of course, this would be a little bit more complicated if field1 and field2 are not string, you'll have to use something like that
SqlFunctions.StringConvert((double)m.field1) + "~" + //etc.
Solution 3
you do this in two step, assuming you will have "not too much result" with a partial match (on only one field)
var field1Collection = joinedCollection.Select(m => m.field1);
var result = entity.Where(m => joinedCollection.Contains(m.field1)).ToList();
then you make the "complete join" on the two enumerated lists...
Solution 4
use a stored procedure / generated raw sql...
Just understood the problem better. You want all rows where the columns match, may be this will help:
myDBTable.Where(x =>
myStaticCollection.Any(y => y.Col2 == x.Col2) &&
myStaticCollection.Any(y => y.Col1 == x.Col1))
.ToList()
.Select(x => new Search { Col1 = x.Col1, Col2 = x.Col2 });
This is saying, I want each row where any Col2 in my static collection matches this database Col2 AND where any Col1 matches this database Col1
this.context.Searches.Join(
this.context.Tabbs,
s => s.Col2,
t => t.Col2,
(search, tab) => new {
search,
tab
});
This will bring back IEnumerable<'a> containing a search and a tab
This guy is doing something similar LINK
var result = from x in entity
join y in entity2
on new { x.field1, x.field2 } equals new { y.field1, y.field2 }
Once you have your result then you want to enumerate that to make sure you're hitting the database and getting all your values back. Once they're in memory, then you can project them into objects.
result.ToList().Select(a => new MyEntity { MyProperty = a.Property });
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 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)
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.