【问题标题】:Entity Framework : Why this code doesn't work实体框架:为什么此代码不起作用
【发布时间】:2015-04-13 16:15:05
【问题描述】:

我正在使用实体框架 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)

产生相同的奇怪类型。

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

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

谢谢!

【问题讨论】:

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


【解决方案1】:

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

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

例如参考EF returning proxy class instead of actual entityWorking with Proxies

如果您想找出由代理包装的实体的底层类型,即与您正在查找的类型匹配的类型(例如MyObject),您可以使用对象上下文:

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

【讨论】:

  • 谢谢,我用过你的代码,但现在是一行,仍然继续保留代理。行:Dim result = methodInfo.Invoke(context, Nothing),返回 MyObject_F2FFE64DA472EB2B2BDF7E143DE887D3845AD9D1731FD3107937062AC0C2E4BB。而且我的代码仍然没有复制任何东西。所以问题是我注意到了,还是其他?
  • 您是否在代码中将Dim myType = entity.GetType() 替换为Dim myType = ObjectContext.GetObjectType(entity.GetType())?因为那样它应该获取context.CreateObject&lt;MyObject&gt;() 的方法信息。当你打电话给Dim methodInfo = context.GetType().GetMethod("CreateObject").MakeGenericMethod(myType)
  • 是的,我已经替换了,但还是行 Dim result = methodInfo.Invoke(context, Nothing) ,返回 MyObject_F2FFE64DA472EB2B2BDF7E143DE887D3845AD9D1731FD3107937062AC0C2E4BB
  • 啊,我明白了。是的,对contect.CreateObject&lt;MyObject&gt;() 的调用也将返回一个代理实例。请注意,可以在数据库上下文的构造函数中禁用代理,使用 Configuration.ProxyCreationEnabled = false
  • 是的,但我正在使用延迟加载,我需要这个。是否可以临时使用您的代码,然后重新启用?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-25
  • 1970-01-01
  • 2015-07-24
  • 1970-01-01
  • 2011-09-02
  • 2013-01-10
相关资源
最近更新 更多