实体框架:为什么这段代码不起作用 [英] Entity Framework : Why this code doesn't work

查看:166
本文介绍了实体框架:为什么这段代码不起作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

 导入System.Data.Objects 
导入System.Data.Objects.DataClasses
导入System.Runtime.CompilerServices

公共模块实体
< Extension()>
公共函数CloneEntity(Of As As Class)(entity As T,context As ObjectContext,Optional include As List(Of IncludeEntity)= Nothing,Optional copyKeys As Boolean = False)As T
返回CloneEntityHelper (上下文,包括,copyKeys)
结束函数

私有函数CloneEntityHelper(Of As As Class)(entity As T,context As ObjectContext,Optional include As List(Of IncludeEntity)= Nothing,可选的copyKeys As Boolean = False)As T
如果include Is Nothing然后include =新列表(包含实例)()
Dim myType = entity.GetType()
Dim methodInfo = context.GetType ().GetMethod(CreateObject)。MakeGenericMethod(myType)
Dim result = methodInfo.Invoke(context,Nothing)
Dim propertyInfo = entity.GetType()。GetProperties()
每个信息在propertyInfo
Dim attributes = info.GetCustomAttributes(GetType(EdmScalarPropertyAttribute),False).ToList()

对于每个attr作为EdmScalarPropertyAttribute在属性
如果(不是copyKeys)AndAlso attr.EntityKeyProperty
继续为
结束如果

info.SetValue(result,info.GetValue(entity,Nothing),Nothing)
Next
如果info.PropertyType.Name.Equals(EntityCollection \"1,StringComparison.OrdinalIgnoreCase)然后
Dim shouldInclude = include.SingleOrDefault(Function(i)i.Name.Equals(info.Name, StringComparison.OrdinalIgnoreCase))
如果shouldInclude是Nothing然后继续为
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每个孩子在relatedChildren
Dim cloneChild = CloneEntityHelper(child,context,shouldInclude.Children, shouldInclude.CopyKeys)
children.Add(cloneChild)
下一个
info.SetValue(result,children,Nothing)
End If
Next

返回结果
结束函数

公共类IncludeEntity
公共属性名称作为字符串

公共属性儿童作为新列表(IncludeEntity)

公共属性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
结束类
结束模块

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

  Dim litm,newitm As New MyObject 
Dim inc =新列表(IncludeEntity)()
inc.Add(New IncludeEntity(Child_list))
litm = context.MyObjects.FirstOrDefault
newitm = litm.CloneEntity (CType(context,Entity.Infrastructure.IObjectCont extAdapter).ObjectContext,include:= inc)

代码执行没有错误,但没有复制,所以 newitm 是空的。



我已经检查了代码,发现这行在$ c> CloneEntity function:

  Dim myType = entity.GetType()

产生一种奇怪的类型。



我期待着类型将为 MyObject 类型,而是返回:

  MyObject_F2FFE64DA472EB2B2BDF7E143DE887D3845AD9D1731FD3107937062AC0C2E4BB 

这一行也是:

  Dim result = methodInfo.Invoke(context,Nothing)

产生相同奇怪的类型。



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



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



谢谢!

解决方案

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




  • 当您访问这些集合属性时,懒惰加载包含在您的实体中的属性的任何集合的内容。

  • 检测您作为脏检查的一部分对实例的属性进行了更改,以便在调用
  • 时,将知道哪些对象是脏的并且需要保存到数据库中code> SaveChanges



参考例如EF返回代理类而不是实际实体使用代理



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

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


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!

解决方案

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());

这篇关于实体框架:为什么这段代码不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆