|
Yes , now I'm using this code :
Dim t a type
Dim s as string = "MyProg1.Child1,MyProg1,Version=1.0.0, Culture=neutral,PublicKeyToken=null"
t=System.Type.GetType(s)
But the problem is that the t get this value : "MyProg1.Child1" , I'm expecting to have just "Child1"
What's the problem ?
|
|
|
|
|
It's one and the same; unless you have multiple classes named "Child1" in your solution, then "Child1" may or may not be the same as "MyProg1.Child1".
If the brain were so simple we could understand it, we would be so simple we couldn't. — Lyall Watson
|
|
|
|
|
Ok , but then why when I use :
CTypeDynamic(Element,Child1)
everything is ok with my CopyEntity function.
Whe I use :
Dim t a type
Dim s as string = "MyProg1.Child1,MyProg1,Version=1.0.0, Culture=neutral,PublicKeyToken=null"
t=System.Type.GetType(s)
CtypeDynamic(Element,t)
I'm still getting the error :
An unhandled exception of type 'System.InvalidOperationException' occurred in EntityFramework.dll
Additional information: The entity type Object is not part of the model for the current context.
|
|
|
|
|
I'm trying to replicate it.. it's not actually CTypeDynamic(Element,Child1) how your working code looks like, is it? Is it CTypeDynamic(Element, GetType(Child1)) or CTypeDynamic<Child1>(Element) ?
If the brain were so simple we could understand it, we would be so simple we couldn't. — Lyall Watson
|
|
|
|
|
Sorry Friend.
It's my mistake.
Now it's confirmed : The CloneEntity Function is working correctly when I pass the element that I get from the expression :
Dim element = CType(Enumerable.ElementAt(CallByName(MyObj1, "Child1", CallType.Get), k), Child1)
But is not working correctly when I pass the element that I get from this expression :
Dim element = CTypeDynamic(Enumerable.ElementAt(CallByName(MyObj1, "Child1", CallType.Get), k), Type.GetType("MyProg1.Child1,MyProg1,Version=1.0.0, Culture=neutral,PublicKeyToken=null"))
|
|
|
|
|
Yes, in the meantime I replicated it - both versions, simplified here:
Dim el = Enumerable.ElementAt(CallByName(MyClass, "Children", CallType.Get), 1)
Dim el1 = CType(el, ChildClass)
Dim el1copy = CopyEntity(el1)
Dim el2 = CTypeDynamic(Of ChildClass)(el)
Dim el2copy = CopyEntity(el2)
Dim el3 = CTypeDynamic(el, GetType(ChildClass))
Dim el3copy = CopyEntity(el3) That's basically the same as your code above. And it's still the same as what I'm talking about for the last messages
I know you can't use 1 and 2. The reason they work is because the return type of CType(el, ChildClass) and CTypeDynamic(Of ChildClass)(el) is ChildClass. The reason 3 doesn't work is because the return type of CTypeDynamic(el, GetType(ChildClass)) is Object (so it doesn't have anything to do with Type.GetType(..)). So, for 1 and 2 CopyEntity(..) is called for the correct generic type, for 3 it's called with Object as generic type. I don't know if there's a way to make 3 work. I tested the same thing (as 3) in C# and it actually works. Either VB differs there from C# or I just don't know how to do it in VB. I can assure you though that the reflection-approach that I suggested would work. If you want to find out if there is a way to make 3 work I would suggest you post a new question so that someone who knows VB better than me will be more likely to notice.
If the brain were so simple we could understand it, we would be so simple we couldn't. — Lyall Watson
|
|
|
|
|
Thank you !
Please , can you post here the code ( of variant 3 ) that works on C# ? ( I mean the whole code that you have tested , with the Copyentity function too ).
Thank you !
|
|
|
|
|
Sure, here you go:
class ChildClass
{ }
class MyClass
{
public ICollection<ChildClass> Children { get; set; }
public MyClass()
{
Children = new HashSet<ChildClass>() { new ChildClass() };
}
}
T CopyEntity<T>(T entity)
where T : class, new()
{
T copy = new T();
return copy;
}
void Test()
{
MyClass myClass = new MyClass();
dynamic children = typeof(MyClass).GetProperty("Children").GetValue(myClass);
dynamic child = Enumerable.ElementAt(children, 0);
dynamic copy = CopyEntity(child);
}
If the brain were so simple we could understand it, we would be so simple we couldn't. — Lyall Watson
modified 15-Apr-15 20:35pm.
|
|
|
|
|
Thank you !
But your code in C# when is converted in vb.net ( with code converters ) , is :
Class ChildClass
End Class
Class [MyClass]
Public Property Children() As ICollection(Of ChildClass)
Get
Return m_Children
End Get
Set
m_Children = Value
End Set
End Property
Private m_Children As ICollection(Of ChildClass)
Public Sub New()
Children = New HashSet(Of ChildClass)() From { _
New ChildClass() _
}
End Sub
End Class
Private Function CopyEntity(Of T As {Class, New})(entity As T) As T
Dim copy As New T()
' actual copying omitted here
' for testing only the return type matters
Return copy
End Function
Private Sub Test()
Dim [myClass] As New [MyClass]()
Dim children As dynamic = GetType([MyClass]).GetProperty("Children").GetValue([myClass])
Dim child As dynamic = Enumerable.ElementAt(children, 0)
Dim copy As dynamic = CopyEntity(child)
' copy is of type ChildClass
End Sub
and this code is not using CTypeDynamic. So what you have tested in vb.net that doesn't work ?
and on my vb.net code , the error came up on the line :
Dim en = ctx.Entry(clone)
and you don't have a such line in your code.
.............................
Also I try to implement your version with reflection , but I can't make it work on vb.net ? can you provide some more
help ?
..............................
Thank you !
modified 16-Apr-15 1:20am.
|
|
|
|
|
dilkonika wrote: and this code is not using CTypeDynamic. Because it works without it. For completeness, I included the analog into the VB-version:
Public Class ChildClass
End Class
Public Class SomeClass
Public Property Children As ICollection(Of ChildClass) = New HashSet(Of ChildClass)
End Class
Public Function CopyEntity(Of T As {Class, New})(entity As T) As T
Dim clone As New T()
Return clone
End Function
Sub Main()
Dim someClass = New SomeClass
someClass.Children.Add(New ChildClass)
Dim el = Enumerable.ElementAt(CallByName(someClass, "Children", CallType.Get), 0)
Dim elcopy = CopyEntity(el)
Dim el1 = CType(el, ChildClass)
Dim el1copy = CopyEntity(el1)
Dim el2 = CTypeDynamic(Of ChildClass)(el)
Dim el2copy = CopyEntity(el2)
Dim el3 = CTypeDynamic(el, GetType(ChildClass))
Dim el3copy = CopyEntity(el3)
End Sub
Quote: and on my vb.net code , the error came up on the line :
Dim en = ctx.Entry(clone)
and you don't have a such line in your code. Because the reason why it not works (when it not works) is because clone is of type Object and not of type ChildClass. So I only have to check for the type of clone to know if your line ctx.Entry(clone) would work.
dilkonika wrote: Also I try to implement your version with reflection , but I can't make it work on vb.net ? can you provide some more
help ? Please post what you have so far.
If the brain were so simple we could understand it, we would be so simple we couldn't. — Lyall Watson
|
|
|
|
|
Thank you !
But for the Reflection version , I just converted the code to vb.net but I don't know how to integreate with my code. If you can just post your full version for C# with reflection so I can understand more ( I don't have so much knowledge about reflection , but at this point I really need a solution for my problem , so I need to use it )
|
|
|
|
|
class Program
{
class ChildClass
{ }
class SomeClass
{
public ICollection<ChildClass> Children { get; set; }
public SomeClass()
{
Children = new HashSet<ChildClass>() { new ChildClass() };
}
}
public static T CopyEntity<T>(T entity)
where T : class, new()
{
T copy = new T();
return copy;
}
static void Main(string[] args)
{
SomeClass someClass = new SomeClass();
dynamic children = typeof(SomeClass).GetProperty("Children").GetValue(someClass);
object child = Enumerable.ElementAt(children, 0);
MethodInfo mi = typeof(Program).GetMethod("CopyEntity", BindingFlags.Static | BindingFlags.Public);
mi = mi.MakeGenericMethod(new Type[] { child.GetType() });
object clone = mi.Invoke(null, new object[] { child });
}
}
If the brain were so simple we could understand it, we would be so simple we couldn't. — Lyall Watson
|
|
|
|
|
Thank you !
Your code is working.
Just for curiosity , the other variant is working too.
I found this solution in vb.net , to make a change on CopyEntityFunction like this :
instead of
Dim clone as New(T)
I use this :
Dim clone = Activator.CreateInstance(entity.GetType())
Now it's working.
Thank you for your help.
|
|
|
|
|
dilkonika wrote: Dim clone = Activator.CreateInstance(entity.GetType()) Yes, that's a simpler solution if you don't need CopyEntity to be generic (that is, if you don't need the static type T for anything else). If you haven't already, you can remove that generic stuff from the declaration of CopyEntity then.
dilkonika wrote: Thank you for your help. You're welcome.
If the brain were so simple we could understand it, we would be so simple we couldn't. — Lyall Watson
|
|
|
|
|
Hello !
This is a code that is supposed to do a copy of an entity framework object with the childs collection that the user want.
Imports System.Data.Objects
Imports System.Data.Objects.DataClasses
Imports System.Runtime.CompilerServices
Public Module Entities
<Extension()>
Public Function CloneEntity(Of T As Class)(entity As T, context As ObjectContext, Optional include As List(Of IncludeEntity) = Nothing, Optional copyKeys As Boolean = False) As T
Return CloneEntityHelper(entity, context, include, copyKeys)
End Function
Private Function CloneEntityHelper(Of T As Class)(entity As T, context As ObjectContext, Optional include As List(Of IncludeEntity) = Nothing, Optional copyKeys As Boolean = False) As T
If include Is Nothing Then include = New List(Of IncludeEntity)()
Dim myType = entity.GetType()
Dim methodInfo = context.GetType().GetMethod("CreateObject").MakeGenericMethod(myType)
Dim result = methodInfo.Invoke(context, Nothing)
Dim propertyInfo = entity.GetType().GetProperties()
For Each info In propertyInfo
Dim attributes = info.GetCustomAttributes(GetType(EdmScalarPropertyAttribute), False).ToList()
For Each attr As EdmScalarPropertyAttribute In attributes
If (Not copyKeys) AndAlso attr.EntityKeyProperty
Continue For
End If
info.SetValue(result, info.GetValue(entity, Nothing), Nothing)
Next
If info.PropertyType.Name.Equals("EntityCollection`1", StringComparison.OrdinalIgnoreCase) Then
Dim shouldInclude = include.SingleOrDefault(Function(i) i.Name.Equals(info.Name, StringComparison.OrdinalIgnoreCase))
If shouldInclude Is Nothing Then Continue For
Dim relatedChildren = info.GetValue(entity, Nothing)
Dim propertyType As Type = relatedChildren.GetType().GetGenericArguments().First()
Dim genericType As Type = GetType(EntityCollection(Of ))
Dim boundType = genericType.MakeGenericType(propertyType)
Dim children = Activator.CreateInstance(boundType)
For Each child In relatedChildren
Dim cloneChild = CloneEntityHelper(child, context, shouldInclude.Children, shouldInclude.CopyKeys)
children.Add(cloneChild)
Next
info.SetValue(result, children, Nothing)
End If
Next
Return result
End Function
Public Class IncludeEntity
Public Property Name As String
Public Property Children As New List(Of IncludeEntity)
Public Property CopyKeys As Boolean
Public Sub New(propertyName As String, ParamArray childNodes() As String)
Name = propertyName
Children = childNodes.Select(Function(n) new IncludeEntity(n)).ToList()
End Sub
End Class
End Module
Now , I use the above code like that :
Dim litm, newitm As New MyObject
Dim inc = New List(Of IncludeEntity)()
inc.Add(New IncludeEntity("Child_list"))
litm=context.MyObjects.FirstOrDefault
newitm = litm.CloneEntity(CType(context, Entity.Infrastructure.IObjectContextAdapter).ObjectContext,include:=inc)
The problem is that nothing is copied.
What's wrong with my code ?
Thank you !
|
|
|
|
|
Please include your class-definition of MyObject (you can omit the methods, if it has any).
Did you already observe it in debug-mode?
|
|
|
|
|
Thank you !
I put some breakpoints , and I have detected that maybe the problem may be this line : Dim attributes = info.GetCustomAttributes(GetType(EdmScalarPropertyAttribute), False).ToList() .
The attributes always have the Length=0 , so all the codes inside the For Each info In propertyInfo doesn;t get executed , and goes to next for each info and so at the end the result is an empty object. What can I do ?
also I did another test ( maybe a stupid test but anyway ) :
I put the line info.SetValue(result, info.GetValue(entity, Nothing), Nothing)
after the next so outside the for loop.
Now the entity is copied , but not the child that is included on inc variable. ?
The code is supposed to work will any kind of classes , but anyway this are the classes where I made the tests:
Partial Public Class Myobject
Public Property id As Integer
Public property name as string
Public Overridable Property Child_list As ICollection(Of Child_list) = New HashSet(Of Child_list)
End Class
Partial Public Class Child_list
Public Property id As Integer
Public Property date1 as DateTime
Public Property quantity as Integer
Public Property ParentID as integer
Public Overridable Property MyObj1 As MyObject
End Class
|
|
|
|
|
Correct, the code you have there is expecting an EdmScalarPropertyAttribute on each field or property that should be copied (with the exception of EntityCollections). You didn't decorate the properties of your class with this attribute, so the SetValue(..)-line was skipped.
Note: I'm not familiar with EF. My following advice should make your CloneEntity-code work (or at least "almost working") but someone who knows about EF might have more to say about it. In particular, I have no idea where the id of your classes gets initialized; if you have to deal with that yourself or if it's somehow magically done for you.
That should be it I think..
|
|
|
|
|
|
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 Function
But look how an object is cloned on my case :
( I want to clone a student and its Results )
Student ID......... Name........Age
1...........George........21
Course_ID..........Description Type
1.....................Math........1
Result_ID..........Course_ID......Student_ID..... Point
1......................1...............1..........30
And after the cloning :
Student ID......... Name........Age
1...........George........21
2...........George........21
Course_ID..........Description Type
1.....................Math...........1
2.....................Math...........1
Result_ID..........Course_ID......Student_ID..... Point
1......................1...............1..........30
2......................2...............2..........30
So now are 2 courses with name "Math". but I don't want to clone the courses.
How to resolve this problem ?
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.
|
|
|
|
|