I have a Type MenuItem that has one-to-many relationship with itself through Children property.
public class MenuItem
{
//Some properties
public IList<MenuItem> Children{get; set;}
}
Now Is there any way in Linq-To-NH to fetch all children until leaf level (not just direct children) for a node.
They seem to have a way to do it using join fetch:
http://ayende.com/blog/4151/nhibernate-tips-tricks-efficiently-selecting-a-tree
http://nhibernate.hibernatingrhinos.com/16/how-to-map-a-tree-in-nhibernate
Related
I have an requirement to show a binary tree like structure on the web page that will
be used to represent parent-child relation. Unlike binary tree, this tree can have multiple child nodes
and the childs can have further children and this process will continue until no child left of their parent.
So, I am pretty much confused on how should my data-model should be and my thinking is not going beyond this one
public class Parent
{
public string parentName {get;set;} // As their will be one start for this tree, I will have one parent node that will show the parent
public List<string> child {get;set;} // As the parent can have multiple children, I can have a list of string
}
But the question is that the child can also act as parent as they can also have children. How should I
implement such structure.
Thanks
A string can't have child elements of its own, so it's not a good representation.
A simple way is to make the child elements simply a List of the same type of element as the parent. Let's call them all Node instead:
public class Node
{
public string Name { get; set; }
public List<Node> ChildNodes { get; set; }
}
I basically have a pretty simple setup of a one-to-many parent-child relationships. E.g.:
public class Parent
{
public Guid Id { get; set; }
public virtual ICollection<Child> Children { get; set; }
}
public class Child
{
public Guid Id { get; set; }
public Guid ParentId { get; set; }
public virtual Parent Parent { get; set; }
}
This is configured using FluentValidation as:
public ChildConfiguration()
{
ToTable("children");
HasKey(c => c.Id);
Property(c => c.Id).HasColumnName("id");
HasRequired(c => c.Parent).WithMany(p => p.Children);
}
I now have an API that provides the list of children for a parent, but I don't want to add the list of children to the existing list every time. Instead I want to delete all existing children to replace them with the list of new ones.
I tried doing so by fetching the parent, clearing the current list of children and adding the new ones.
var parent = await _repository.GetById(parentId);
parent.Children.Clear();
foreach (var child in children)
{
parent.Children.Add(child);
}
This does not work, as it throws an exception:
The operation failed: The relationship could not be changed because one or more of the foreign-key properties is non-nullable. When a change is made to a relationship, the related foreign-key property is set to a null value. If the foreign-key does not support null values, a new relationship must be defined, the foreign-key property must be assigned another non-null value, or the unrelated object must be deleted.
As I understood this is because it's trying to remove the link between the two entities rather than actually deleting it from the database.
A solution is to directly access the Children in the DbContext and do a RemoveRange as:
DbContext.Children.RemoveRange(children);
But I don't want to expose my Children entity directly on the context. Instead I always want to go through the Parent. So I could create a method in the repository like:
var parent = DbContext.Parents.Find(parentId);
foreach (var child in parent.Children.ToList())
{
parent.Remove(child);
}
But this is throwing the same exception and I don't understand why as I think I am explicitly telling EF to remove the child from the parent.
Is there a way to remove the children from the DB without accessing them directly on the DbContext?
Thanks!
Guid is a struct and struct is non-nullable type like primitive types.
eg : int, double, bool, etc...
You will be able to delete the children of a given parent with your following code
var parent = await _repository.GetById(parentId);
parent.Children.Clear();
foreach (var child in children)
{
parent.Children.Add(child);
}
by declaring your Guid ParentId property in you Child class Nullable like this Nullable<Guid>.
I have a collection of items coming from a database which has a parentid value or null.
Here is my class design:
public class Item
{
public int id{get;set;}
public string Name{get;set;}
public int? ParentId{get;set;}
public List<Item> SubItems{get;set;}
}
I want to build a hierarchical structure of Items from the collection. Assume a collection is 100 items from which I need to construct the structure based on the ParentId mapping.
I tried this post Recursive Hierarchical Joins in C# and LINQ
but it gives me an error if ParentId is null.
Also tried Build tree type list by recursively checking parent-child relationship C# , but this solution also does not work for me.
How do I achieve this?
You could use this approach:
Get all the items from the database (without filling the SubItems).
Build a Lookup<int?,Item> of parent ids and items with that parent id.
Loop through the items and associate each item with the subitems using the lookup.
Code:
var items = // get from the database... (e.g. as a list)
var lookup = items.ToLookup(x => x.ParentId);
foreach (var item in items)
item.SubItems = lookup[item.Id].ToList();
As #EamonNerbonne commented below, you can get the root elements as well, if you need to:
var roots = lookup[null].ToList();
Using this Node class you can simply do this:
var flatListOfItems = GetItemsFromDatabase();
var rootNodes =Node<Item>.CreateTree(flatListOfItems, i => i.id, i => i.ParentId);
Your items doesn't need the subitems anymore because the Node class has a children and a descendants property. (Also ancestors, siblings, level etc.).
The CreateTree method results in 1 or more rootnodes. If you are sure that there is always 1 rootnode, you can do rootNodes.Single() to get the root.
Do you really need a setter for sub items? Also be mindful of the performance issues when you run Select* queries on SQL server.
public List<Item> SubItems{
get
{
try{
var validParents = db.items.Where(x=>x.ParentId!=null && x.ParentId.Equals(Id)); //db is your dbcontext
if(validParents !=null)
{
return validParents.ToList();
}else
{
return null;
}
catch(Exception)
{
return null;
}
}
(Note: Think of adding this to your partial entity class. Never name your entity as "Item" :).Item is a reserved word. )
As part of an MVC app I have two classes which map to the appropriate tables in my database
public class Child {
public int id;
public int parentId; //foreign key to parent class
public int age;
}
public class Parent {
public int id;
public virtual IList<Child> children;
}
In my controller I need to select only one parent by the id, including its list of children.
With the parent that gets selected, I want that parent's list of children to be in order of age.
I have been able to do this with the following code:
Parent parent = context.parents.FirstOrDefault(p => p.id == idToCheck);
parent.children = parent.children.OrderBy(c => c.age).Cast<Child>().ToList();
Even though this works, I am left with the feeling that this is a hackish way to do what I'm after.
From what I've read, it is not possible to order children when I initially select the parent. Is that correct?
Is there anything I am doing in the above code that could/should be done better?
I have a List<Leaf> named items in C#. A Leaf has the following properties:
public class Leaf
{
public int ID { get; set; }
public int ParentID { get; set; }
public bool IsFlagged { get; set; }
}
If a Leaf has the IsFlagged property set then I need to remove it from the collection of items. In addition, I need to remove all of that Leaf entity's children. I'm trying to figure out the most elegant way to write this code. Currently, I have a loop within a loop, but it seems sloppy.
Does anyone know of an elegant way to do this?
Perhaps:
void RemoveItAndChildren(Leaf leaf)
{
foreach (Leaf item in items)
if (item.ParentID == leaf.ID)
RemoveItAndChildren(item);
items.Remove(leaf);
}
And use so:
foreach (Leaf leaf in items)
if (leaf.IsFlagged)
RemoveItAndChildren(leaf);
Note that, as in a comment above, something like the following might be more appropriate:
public class Leaf2
{
List<Leaf2> Children;
bool IsFlagged { get; set; }
}
Most reasonable (and probably "the most elegant") way of dealing with tree is to store it as a tree, not an array/list. In this case you'll not need to deal with walking elements to try to find all children.
Note that depending on your actual requirements tree may not be best data structure, but for removing node with all children nodes it would be hard to beat regular tree.