问题
I'm using Entity Framework 6.0, DbContext. I'm using this method to copy an object and some related children:
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'm using the code like below :
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 code is executed without errors, but nothing is copied, so newitm
is empty.
I have inspected the code and found that this line on the CloneEntity
function :
Dim myType = entity.GetType()
Is producing a strange type.
I'm expecting that the type will be of MyObject
type, but instead this return :
MyObject_F2FFE64DA472EB2B2BDF7E143DE887D3845AD9D1731FD3107937062AC0C2E4BB
This line too :
Dim result = methodInfo.Invoke(context, Nothing)
produces the same strange type.
I don't know if this is the problem, but this is the only strange thing I have noticed.
Can you help me to find out why this code doesn't work?
Thank you!
回答1:
Entity framework, like many other ORMs will build a proxy type for your entities so that it can intercept calls to:
- Lazy load the contents of any collection contained as properties within your entity, when you access those collection properties.
- Detect that you have made changes to the properties of an instance as part of dirty checking, so that it will know which objects are dirty and need to be saved to the database when you invoke
SaveChanges
.
Refer for example to EF returning proxy class instead of actual entity or Working with Proxies.
If you want to find out the underlying type of your entity that is wrapped by the proxy, i.e. the one that would match with the type you are looking for (e.g. MyObject
), you can do that using a method in the object context:
var underlyingType = ObjectContext.GetObjectType(entity.GetType());
来源:https://stackoverflow.com/questions/29598831/entity-framework-why-this-code-doesnt-work