Entity Framework : Clone an object and only its childs
-
Hello ! I have see several methods around for deep cloning an entity framework object. All these methods use serialization. But sometimes these methods are not creating what I want. For example I try to use the Json.net (http://www.newtonsoft.com/json[^]) to serialize and after to deserialize a object. And after I use this code to clone :
<Extension> _
Public Function CloneJson(Of T)(source As T) As T
If [Object].ReferenceEquals(source, Nothing) Then
Return Nothing
End If
Return JsonConvert.DeserializeObject(Of T)(JsonConvert.SerializeObject(source))
End FunctionBut look how an object is cloned on my case : ( I want to clone a student and its Results )
Student ID......... Name........Age
1...........George........21Course_ID..........Description Type
1.....................Math........1Result_ID..........Course_ID......Student_ID..... Point
1......................1...............1..........30And after the cloning :
Student ID......... Name........Age
1...........George........21
2...........George........21Course_ID..........Description Type
1.....................Math...........1
2.....................Math...........1Result_ID..........Course_ID......Student_ID..... Point
1......................1...............1..........30
2......................2...............2..........30So now are 2 courses with name "Math". but I don't want to clone the courses. How to resolve this problem ? Thank you !
-
Hello ! I have see several methods around for deep cloning an entity framework object. All these methods use serialization. But sometimes these methods are not creating what I want. For example I try to use the Json.net (http://www.newtonsoft.com/json[^]) to serialize and after to deserialize a object. And after I use this code to clone :
<Extension> _
Public Function CloneJson(Of T)(source As T) As T
If [Object].ReferenceEquals(source, Nothing) Then
Return Nothing
End If
Return JsonConvert.DeserializeObject(Of T)(JsonConvert.SerializeObject(source))
End FunctionBut look how an object is cloned on my case : ( I want to clone a student and its Results )
Student ID......... Name........Age
1...........George........21Course_ID..........Description Type
1.....................Math........1Result_ID..........Course_ID......Student_ID..... Point
1......................1...............1..........30And after the cloning :
Student ID......... Name........Age
1...........George........21
2...........George........21Course_ID..........Description Type
1.....................Math...........1
2.....................Math...........1Result_ID..........Course_ID......Student_ID..... Point
1......................1...............1..........30
2......................2...............2..........30So now are 2 courses with name "Math". but I don't want to clone the courses. How to resolve this problem ? Thank you !
You could put a
JsonIgnoreAttribute
on the property of the student-class that references the course(s). Which would, as the name implies, exclude it from the serialization and thereby from the cloning. http://www.newtonsoft.com/json/help/html/SerializationAttributes.htm[^] But if you would want to serialize student-objects elsewhere including their courses, that method would obviously not be suitable. In that case you would have to choose a different approach; please refer to: C# Object Clone Wars[^] http://stackoverflow.com/questions/21116554/proper-way-to-implement-icloneable[^] https://msdn.microsoft.com/en-us/library/system.icloneable%28v=vs.110%29.aspx[^] (Might be interesting reads in any case.) -
You could put a
JsonIgnoreAttribute
on the property of the student-class that references the course(s). Which would, as the name implies, exclude it from the serialization and thereby from the cloning. http://www.newtonsoft.com/json/help/html/SerializationAttributes.htm[^] But if you would want to serialize student-objects elsewhere including their courses, that method would obviously not be suitable. In that case you would have to choose a different approach; please refer to: C# Object Clone Wars[^] http://stackoverflow.com/questions/21116554/proper-way-to-implement-icloneable[^] https://msdn.microsoft.com/en-us/library/system.icloneable%28v=vs.110%29.aspx[^] (Might be interesting reads in any case.)sorry , maybe you have misunderstand. The Student class has not reference to Courses. Results class has reference to courses. So as you can see I want to clone the student and its results. But each result has a reference to courses. so the deep cloning methods are duplicating the courses too.
-
You could put a
JsonIgnoreAttribute
on the property of the student-class that references the course(s). Which would, as the name implies, exclude it from the serialization and thereby from the cloning. http://www.newtonsoft.com/json/help/html/SerializationAttributes.htm[^] But if you would want to serialize student-objects elsewhere including their courses, that method would obviously not be suitable. In that case you would have to choose a different approach; please refer to: C# Object Clone Wars[^] http://stackoverflow.com/questions/21116554/proper-way-to-implement-icloneable[^] https://msdn.microsoft.com/en-us/library/system.icloneable%28v=vs.110%29.aspx[^] (Might be interesting reads in any case.)and sorry , but I;m thinking is there any way to have a function that take as argument an object and the child that I want to copy. and just to loop through all the property list of the object and to copy the values to a new object. The same thing with the child. Of course I'm speaking to create a general function that will work on all similar case ( not with a specific object ). Is there any suggestions how I can do that ? Thank you !
-
sorry , maybe you have misunderstand. The Student class has not reference to Courses. Results class has reference to courses. So as you can see I want to clone the student and its results. But each result has a reference to courses. so the deep cloning methods are duplicating the courses too.
Alright - but that doesn't completely invalidate my answer: - If you nowhere else need to serialize results (at least not with Json.Net) then you could use the JsonIgnoreAttribute on the reference to the courses in the results-class. - Else you would have to implement custom methods for cloning in the student- and results-classes for which you find pointers in the links I have provided you.
-
and sorry , but I;m thinking is there any way to have a function that take as argument an object and the child that I want to copy. and just to loop through all the property list of the object and to copy the values to a new object. The same thing with the child. Of course I'm speaking to create a general function that will work on all similar case ( not with a specific object ). Is there any suggestions how I can do that ? Thank you !
As you have seen in the other thread, I've had a small discussion with Eddy Vluggen if his downvote on one of your replies was justified because I initially doubted it. Now I'm starting to realize what he meant by "it's a recurring theme" - because it looks like you don't thoroughly read our replies or don't evaluate provided links before asking again. You would have found the answer to your question above if you had taken a look at my link "C# Object Clone Wars", namely the section "Clone with Reflection" which includes a link to a sample. You should work on that if you want to keep getting responses to your questions. We've answered them so far because we enjoy helping but if you don't value our answers by putting some effort into comprehending them and following provided links, it becomes a bit tiresome.
-
As you have seen in the other thread, I've had a small discussion with Eddy Vluggen if his downvote on one of your replies was justified because I initially doubted it. Now I'm starting to realize what he meant by "it's a recurring theme" - because it looks like you don't thoroughly read our replies or don't evaluate provided links before asking again. You would have found the answer to your question above if you had taken a look at my link "C# Object Clone Wars", namely the section "Clone with Reflection" which includes a link to a sample. You should work on that if you want to keep getting responses to your questions. We've answered them so far because we enjoy helping but if you don't value our answers by putting some effort into comprehending them and following provided links, it becomes a bit tiresome.
On your link in the clone with reflection section , contains just words.
Cloning by Reflection uses Activator.CreateInstance to create a new object of the same type, then performs a shallow copy of each field using Reflection. The advantage of this method is it's automated and does not need to be adjusted when members are added or removed from the object. Also, it can be written to provide a deep copy. The disadvantage is it uses Reflection, which is slower and not allowed in partial trust environments.
I'm asking because I don't know how to start this "Clone with reflection". And for your and someone other opinion about my questions, well I don't care if someone down vote my questions because I'm not in this forum to collect votes. I'm not a specialist like you , and I try to make questions as I think and hope to learn something. If someone doesn't like my questions down vote and ignore them. But I have a little opinion for you specialists ( Maybe I'm wrong , but this is my opinion ) : You judge some of my questions when I ask help how to start a thing ( like this ) and give as a response some links ( it's obvious that this are not your articles , but to someone else that wrote it ) , and on other questions where I provide my code like this http://www.codeproject.com/Messages/5036045/Make-all-the-controls-inside-a-Groupbox-unusable-w.aspx[^] you doesn't try to give an answer at all. If you like helping people just do it without comment , if you don't , down vote the questions and continue to collect votes for yourself. Until I will be I this forum I will continue to make questions ( don't care If I get response or not ) , or if you have the power , close my account and relax yourself.
-
On your link in the clone with reflection section , contains just words.
Cloning by Reflection uses Activator.CreateInstance to create a new object of the same type, then performs a shallow copy of each field using Reflection. The advantage of this method is it's automated and does not need to be adjusted when members are added or removed from the object. Also, it can be written to provide a deep copy. The disadvantage is it uses Reflection, which is slower and not allowed in partial trust environments.
I'm asking because I don't know how to start this "Clone with reflection". And for your and someone other opinion about my questions, well I don't care if someone down vote my questions because I'm not in this forum to collect votes. I'm not a specialist like you , and I try to make questions as I think and hope to learn something. If someone doesn't like my questions down vote and ignore them. But I have a little opinion for you specialists ( Maybe I'm wrong , but this is my opinion ) : You judge some of my questions when I ask help how to start a thing ( like this ) and give as a response some links ( it's obvious that this are not your articles , but to someone else that wrote it ) , and on other questions where I provide my code like this http://www.codeproject.com/Messages/5036045/Make-all-the-controls-inside-a-Groupbox-unusable-w.aspx[^] you doesn't try to give an answer at all. If you like helping people just do it without comment , if you don't , down vote the questions and continue to collect votes for yourself. Until I will be I this forum I will continue to make questions ( don't care If I get response or not ) , or if you have the power , close my account and relax yourself.
dilkonika wrote:
On your link in the clone with reflection section , contains just words.
For me there's a link "Sample Code" following the last sentence, leading to this Codeproject-article: Base class for cloning an object in C#[^]. My point wasn't about collecting votes, neither you nor me. My point is about valuing an answer by spending some time investigating all that is mentioned in it. What is wrong with providing links to resources written by someone else as part of an answer if it's perfectly suitable for answering a part of your question? Though I like to help, somewhere has a cut to be made, else I would end up writing stuff again and again that has already been written. I'm not judging your (initial) questions. So far, those that I've seen, I think they're alright. And there's also nothing wrong with asking again if something isn't understood. But asking again if something was already covered by the previous answer or would only require following a link gives the impression that the effort of writing an answer was for naught and that's kind of disappointing. If for whatever reason the link on that webpage wasn't displayed for you (JavaScript disabled?) I'm sorry to have criticized you for that but you'll have to admit that I shouldn't have to take that rather unusual phenomenon into consideration. Also I don't regard myself an expert or specialist - it just happened that I had an answer for your current question - and I don't have an answer for your other question, otherwise I would have answered it.
-
dilkonika wrote:
On your link in the clone with reflection section , contains just words.
For me there's a link "Sample Code" following the last sentence, leading to this Codeproject-article: Base class for cloning an object in C#[^]. My point wasn't about collecting votes, neither you nor me. My point is about valuing an answer by spending some time investigating all that is mentioned in it. What is wrong with providing links to resources written by someone else as part of an answer if it's perfectly suitable for answering a part of your question? Though I like to help, somewhere has a cut to be made, else I would end up writing stuff again and again that has already been written. I'm not judging your (initial) questions. So far, those that I've seen, I think they're alright. And there's also nothing wrong with asking again if something isn't understood. But asking again if something was already covered by the previous answer or would only require following a link gives the impression that the effort of writing an answer was for naught and that's kind of disappointing. If for whatever reason the link on that webpage wasn't displayed for you (JavaScript disabled?) I'm sorry to have criticized you for that but you'll have to admit that I shouldn't have to take that rather unusual phenomenon into consideration. Also I don't regard myself an expert or specialist - it just happened that I had an answer for your current question - and I don't have an answer for your other question, otherwise I would have answered it.
Yes now I have read this example. But as I see he implement the Icloneable. there are many articles on internet that suggest avoid ICloneable because of Shallow/Deep confusion. instead , I found another way :
<Extension> _
Public Sub CopyTo(Of T)(copyFrom As T, copyTo__1 As T, copyParentProperties As Boolean)
Dim props As PropertyInfo()
If copyParentProperties Then
props = GetType(T).GetProperties()
Else
props = GetType(T).GetProperties(BindingFlags.[Public] Or BindingFlags.Instance Or BindingFlags.DeclaredOnly)
End If
Dim i As Integer = 0
While i < props.Length
Dim propertyValue = copyFrom.[GetType]().GetProperty(props(i).Name).GetValue(copyFrom, Nothing)
copyTo__1.[GetType]().GetProperty(props(i).Name).SetValue(copyTo__1, propertyValue, Nothing)
System.Math.Max(System.Threading.Interlocked.Increment(i), i - 1)
End While
End SubBut when I try to use it like this :
newitm = New Myobject currentobj.CopyTo(newitm, False) context.MyObjects.Add(Newitm) context.savechanges
I get an error on the line context.MyObjects.Add(Newitm):
An unhandled exception of type 'System.InvalidOperationException' occurred in System.Core.dll
Additional information: Collection was modified; enumeration operation may not execute.
(But of course , if i create a new object and fill the properties manually one by one , the ADD method works without problems. ) What may be the problem ? Thank you !
-
Yes now I have read this example. But as I see he implement the Icloneable. there are many articles on internet that suggest avoid ICloneable because of Shallow/Deep confusion. instead , I found another way :
<Extension> _
Public Sub CopyTo(Of T)(copyFrom As T, copyTo__1 As T, copyParentProperties As Boolean)
Dim props As PropertyInfo()
If copyParentProperties Then
props = GetType(T).GetProperties()
Else
props = GetType(T).GetProperties(BindingFlags.[Public] Or BindingFlags.Instance Or BindingFlags.DeclaredOnly)
End If
Dim i As Integer = 0
While i < props.Length
Dim propertyValue = copyFrom.[GetType]().GetProperty(props(i).Name).GetValue(copyFrom, Nothing)
copyTo__1.[GetType]().GetProperty(props(i).Name).SetValue(copyTo__1, propertyValue, Nothing)
System.Math.Max(System.Threading.Interlocked.Increment(i), i - 1)
End While
End SubBut when I try to use it like this :
newitm = New Myobject currentobj.CopyTo(newitm, False) context.MyObjects.Add(Newitm) context.savechanges
I get an error on the line context.MyObjects.Add(Newitm):
An unhandled exception of type 'System.InvalidOperationException' occurred in System.Core.dll
Additional information: Collection was modified; enumeration operation may not execute.
(But of course , if i create a new object and fill the properties manually one by one , the ADD method works without problems. ) What may be the problem ? Thank you !
dilkonika wrote:
there are many articles on internet that suggest avoid ICloneable because of Shallow/Deep confusion.
Yes, I would also avoid it. The solution is to simply name your Clone-Method/Interface differently and let its name express what it does (shallow/deep/configurable). Are you aware that the method CopyTo(..) makes a shallow copy and ignores fields? Basically the only advantage it has over Object.MemberwiseClone[^] is that you have the possibility to specify whether "parent" properties should be copied or not. So if you call it on a Student, it will copy the reference to his Result(s), not make a copy of his Result(s).
dilkonika wrote:
An unhandled exception of type 'System.InvalidOperationException' occurred in System.Core.dll Additional information: Collection was modified; enumeration operation may not execute.
I assume you used this code:
newitm = New Myobject currentobj.CopyTo(newitm, False) context.MyObjects.Add(Newitm) context.savechanges
in a foreach-loop where you iterated over objects (currentobj) in
context
? You can't modify a collection while you're iterating over it using an Enumerator (which is what a foreach-loop does). Your options: - Iterate using a for-loop, if the source collection has an indexer, in reverse direction. - Make a copy of the collection and iterate over this copy while modifying the source collection. - Create a new collection of objects to be added/deleted while iterating the source collection. When finished, add/delete the objects contained in the new collection to/from the source collection. -
dilkonika wrote:
there are many articles on internet that suggest avoid ICloneable because of Shallow/Deep confusion.
Yes, I would also avoid it. The solution is to simply name your Clone-Method/Interface differently and let its name express what it does (shallow/deep/configurable). Are you aware that the method CopyTo(..) makes a shallow copy and ignores fields? Basically the only advantage it has over Object.MemberwiseClone[^] is that you have the possibility to specify whether "parent" properties should be copied or not. So if you call it on a Student, it will copy the reference to his Result(s), not make a copy of his Result(s).
dilkonika wrote:
An unhandled exception of type 'System.InvalidOperationException' occurred in System.Core.dll Additional information: Collection was modified; enumeration operation may not execute.
I assume you used this code:
newitm = New Myobject currentobj.CopyTo(newitm, False) context.MyObjects.Add(Newitm) context.savechanges
in a foreach-loop where you iterated over objects (currentobj) in
context
? You can't modify a collection while you're iterating over it using an Enumerator (which is what a foreach-loop does). Your options: - Iterate using a for-loop, if the source collection has an indexer, in reverse direction. - Make a copy of the collection and iterate over this copy while modifying the source collection. - Create a new collection of objects to be added/deleted while iterating the source collection. When finished, add/delete the objects contained in the new collection to/from the source collection. -
Thank you ! No , I heaven;t used my code in a for-each loop. currentobj=context.myobjects.firstordefault. and after continue with the code I posted.
Could be a quirk in EF. Please try this (two lines switched):
newitm = New Myobject context.MyObjects.Add(newitm) currentobj.CopyTo(newitm, False) context.savechanges