实体框架:为什么此代码不起作用

时间:2015-04-13 06:11:13

标签: vb.net entity-framework system.reflection

我正在使用Entity Framework 6.0,DbContext。我正在使用此方法复制对象和一些相关的子项:

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

现在我正在使用如下代码:

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)

执行代码时没有错误,但没有任何内容被复制,因此newitm为空。

我检查了代码,发现CloneEntity函数上的这一行:

Dim myType = entity.GetType()

产生一种奇怪的类型。

我希望该类型为MyObject类型,而是返回:

MyObject_F2FFE64DA472EB2B2BDF7E143DE887D3845AD9D1731FD3107937062AC0C2E4BB

这一行:

Dim result = methodInfo.Invoke(context, Nothing)

产生相同的奇怪类型。

我不知道这是不是问题,但这是我注意到的唯一奇怪的事情。

你能帮助我找出为什么这段代码不起作用吗?

谢谢!

1 个答案:

答案 0 :(得分:1)

与许多其他ORM一样,实体框架将为您的实体构建代理类型,以便它可以拦截对以下内容的调用:

  • 当您访问这些集合属性时,延迟加载实体中包含的任何集合的内容。
  • 检测您是否对实例的属性进行了更改,作为脏检查的一部分,以便在调用SaveChanges时,它将知道哪些对象是脏的并且需要保存到数据库。

例如,请参阅EF returning proxy class instead of actual entityWorking with Proxies

如果要查找由代理包装的实体的基础类型,即与您要查找的类型匹配的实体(例如MyObject),您可以使用对象上下文中的方法:

var underlyingType = ObjectContext.GetObjectType(entity.GetType());