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?
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 2 models, one of which has a child collection of the other:
[Table("ParentTable")]
public class Parent
{
[Key, Column("Parent")]
public string Id { get; set; }
[Column("ParentName")]
public string Name { get; set; }
public virtual ICollection<Widget> Widgets { get; set; }
}
[Table("WidgetTable")]
public class Widget
{
public string Year { get; set; }
[Column("Parent")]
public string ParentId { get; set; }
public string Comments { get; set; }
[Key, Column("ID_Widget")]
public int Id { get; set; }
[ForeignKey("ParentId"), JsonIgnore]
public virtual Parent Parent { get; set; }
}
This code works for > 99% of widgets:
var parent = _dbContext.Parents.FirstOrDefault(p => p.Id == parentId);
Usually, parent.Widgets is a collection with more than one item. In a couple of instances, however, parent.Widgets is null (not a collection with no items).
I have used Query Analyzer to trace both the query for the parent and the query for widgets belonging to that parent. Both return exactly the rows I expect; however, the model for one or two parent IDs results in a null value for the Widgets collection. What could cause a lazy-loaded collection to be null in some instances but not others?
This situation commonly comes up when a dbContext lifetime is left open across an Add, saveChanges, and then retrieval.
For example:
var context = new MyDbContext(); // holding Parents.
var testParent = new Parent{Id = "Parent1", Name = "Parent 1"};
context.Parents.Add(testParent);
At this point if you were to do:
var result = context.Parents.FirstOrDefault(x=> x.ParentId == "Parent1");
you wouldn't get a parent. Selection comes from committed state.. So...
context.SaveChanges();
var result = context.Parents.FirstOrDefault(x=> x.ParentId == "Parent1");
This will return you a reference to the parent you had inserted since the context knows about this entity and has a reference to the object you created. It doesn't go to data state. Since your definition for Widgets was just defined with a get/set auto-property the Widgets collection in this case will be #null.
if you do this:
context.Dispose();
context = new MyDbContext();
var result = context.Parents.FirstOrDefault(x=> x.ParentId == "Parent1");
In this case the parent is not known by the new context so it goes to data state. EF will return you a proxy list for lazy loading the Widgets, which there are none so you get back an empty list, not #null.
When dealing with collection classes in EF it's best to avoid auto-properties or initialize them in your constructor to avoid this behaviour; you'll typically want to assign Widgets after creating a Parent. Initializing a default member is better because you don't want to encourage ever using a setter on the collection property.
For example:
private readonly List<Widget> _widgets = new List<Widget>();
public virtual ICollection<Widget> Widgets
{
get { return _widgets; }
protected set { throw new InvalidOperationException("Do not set the Widget collection. Use Clear() and Add()"); }
}
Avoid performing a Set operation on a collection property as this will screw up in entity reference scenarios. For instance, if you wanted to sort your Widget collection by year and did something like:
parent.Widgets = parent.Widgets.OrderBy(x=> x.Year).ToList();
Seems innocent enough, but when the Widgets reference was an EF proxy, you've just blown it away. EF now cannot perform change tracking on the collection.
Initialize your collection and you should avoid surprises with #null collection references. Also I would look at the lifetime of your dbContext. It's good to keep one initialized over the lifetime of a request or particular operation, but avoid keeping them alive longer than necessary. Context change tracking and such consume resources and you can find seemingly intermittent odd behaviour like this when they cross operations.
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
Is there anything wrong with defining something like this:
class ObjectA
{
property a;
property b;
List <ObjectA> c;
...
}
No, and because the answer needs at least 30 characters, I'll add that this is a common pattern.
Since you included the oop tag, though, I'll add that this pattern gives a lot of control to the outside world. If c is a list of children, for example, you're giving everyone who has access to an instance of ObjectA the ability to add, delete, or replace its children.
A tighter approach would be to use some sort of read-only type (perhaps implementing IList<ObjectA>) to expose the children.
EDIT
Note that the following still allows others to modify your list:
class ObjectA
{
property a;
property b;
List <ObjectA> c;
...
public List<ObjectA> Children { get { return c; } }
}
The absence of a setter only prevents outsiders from replacing the list object.
Nope. That's perfectly acceptable. Tree structures do this.
It is perfectly valid. For example, you would have to do something like this to build a tree data structure (parent node contains a list of child nodes).
i have to ask if your question is about putting a List< > in there, or if it is about putting a List< ObjectA > inside of ObjectA. and the answer to both questions is "Yes"!
the thing to keep in mind is that by default, the access is private. if you want other classes to use this list, then you need to add a few things to your class...
class ObjectA
{
property a;
property b;
List <ObjectA> c;
// allow access, but not assignment
// you can still modify the list from outside, you just cant
// assign a new list from outside the class
public List<ObjectA> somePropertyName{ get { return this.c;}}
// same as above, only allow derived child classes to set the list
public List<ObjectA> somePropertyName{ get { return this.c;}
protected set { this.c = value;} }
// allow all access
public List<ObjectA> somePropertyName{ get { return this.c;}
set { this.c = value;} }
}
No. This is valid. Many structures uses this graph like pattern.
If you eg have a base collection class
namespace MiniGraphLibrary
{
public class GraphCollection
{
public Node Root { set; get; }
public Node FindChild(Node root)
{
throw new NotImplementedException();
}
public Node InsertNode(Node root, Node nodeToBeInserted)
{
throw new NotImplementedException();
}
}
}
Then you can have the node act like this:
namespace MiniGraphLibrary
{
public class Node
{
private string _info;
private List<Node> _children = new List<Node>();
public Node(Node parent, string info)
{
this._info = info;
this.Parent = parent;
}
public Node Parent { get; set; }
public void AddChild(Node node)
{
if (!this.DoesNodeContainChild(node))
{
node.Parent = this;
_children.Add(node);
}
}
public bool DoesNodeContainChild(Node child)
{
return _children.Contains(child);
}
}
}
Note that this is something I wrote in 2 minutes, and it is problery not good in production, but the 2 main things is that you have a parent node and many children. When you add a child node to a given node, then you make sure that it has its parent node set. Here I first check if the child is allready in the children list before connection the two.
You could make some changes to the code, and make sure that if a child is removed an parent lists that it is allready connected to. I have not done this there.
I have made this to illustrate how it could be used. And it is used many places. Fx clustered indexes in MSSQL uses some sort of this tree like representation. But I am NOT an expert on this subject, so correct me if I am wrong.
I have not implemented the two classes in the GraphCollection class. The downside of my little example is that you if you are going to implement the Find method, then you have to go through the whole graph. You could make a binary tree that only has two children:
namespace MiniTreeLibrary
{
public class SimpleNode
{
private string _info;
private SimpleNode _left;
private SimpleNode _right;
private SimpleNode _parent;
public SimpleNode(Node parent, string info)
{
this._info = info;
this.Parent = parent;
}
public Node Parent { get; private set; }
}
}
I have omitted the insertion of the right and left. Now with this binary tree you could do some pretty darn fast searching, if you wanted!! But that is another discossion.
There is many rules when it comes trees and graphs, and my graph is even a real graph. But I have put these examples here so you can see that it is used alot!! If you want to go more into linear and other data structures, then see this serie of articles. Part 3, 4 and 5 they talks alot more about trees and graphs.