EF 中的可序列化类和动态代理 - 如何? [英] Serializable classes and dynamic proxies in EF - how?

查看:29
本文介绍了EF 中的可序列化类和动态代理 - 如何?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

[之前的帖子] 中,我走上了必须克隆的道路我的实体.我尝试使用 [codeproject].

In [a previous posting], I was set on the path to having to clone my entities. This I've attempted to do with a serialisation approach as found in [codeproject].

因为类是由实体框架生成的,所以我在自定义 .cs 中单独标记它们,如下所示:

because the classes are generated by Entity Framework, I mark them up separately in a custom .cs like this:

[Serializable]
public partial class Claims
{
}

然而,当检查(在克隆方法中):

however, when the check (in the clone method):

if (Object.ReferenceEquals(source, null))
{

被击中,我得到错误:

System.ArgumentException was unhandled by user code
  Message=The type must be serializable.
Parameter name: source
  Source=Web
  ParamName=source
  StackTrace:
       at .Web.Cloner.Clone[T](T source) in C:Users.DocumentsVisual Studio 2010Projects.WebsiteExtensions.Object.cs:line 49
       at .Web.Models.Employer..ctor(User u) in C:Users.DocumentsVisual Studio 2010Projects.WebsiteModelsEF.Custom.cs:line 121
       at .Web.Controllers.AuthController.Register(String Company, String GivenName, String Surname, String Title, String Department) in C:Users.DocumentsVisual Studio 2010Projects.WebsiteControllersAuthController.cs:line 119
       at lambda_method(Closure , ControllerBase , Object[] )
       at System.Web.Mvc.ActionMethodDispatcher.Execute(ControllerBase controller, Object[] parameters)
       at System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters)
       at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters)
       at System.Web.Mvc.ControllerActionInvoker.<>c__DisplayClass15.<InvokeActionMethodWithFilters>b__12()
       at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func`1 continuation)
  InnerException: 

很明显,虽然我的类 Claims 是可序列化的,但 EF 生成的动态代理不是......不知何故我的装饰没有流过.

so apparently whilst my class Claims is serialisable, the dynamic proxies generated by EF are not... somehow my decorations are not flowing through.

这里有什么技巧?

* 更新我 *

更多上下文:我有一个 User 类,它包含一个属性 Claims,定义为 ICollection.进行克隆时,传递的类型是集合,而不是 Claim - 这解释了为什么克隆器抱怨该类型不可序列化.所以现在的问题是:如何使 User.Claims 可序列化,因为我无法装饰属性?

for more context: I have a class User which contains a property Claims defined as an ICollection<Claim>. when doing the cloning, the type that gets passed is the collection, not Claim - this explains why the cloner is complaining that the type is not serializable. so the question now is: how do I make User.Claims serializable since I can't decorate a property?

Error   1   Attribute 'Serializable' is not valid on this declaration type.
It is only valid on 'class, struct, enum, delegate' declarations.   
C:Users.DocumentsVisual Studio 2010Projects.WebsiteModelsEF.Custom.cs
128 10  Website

* 更新二 *

练习的重点是创建一个深拷贝.这是它的样子:

the point of the exercise is to facility a deep copy. this is what it looks like:

public partial class Employer
{
    public Employer(User u)
    {
        this.Id = u.Id;
        this.GivenName = u.GivenName;
        this.Surname = u.Surname;
        this.Claims = u.Claims.Clone();
        this.Contacts = u.Contacts.Clone();
    }
}

为了使 u.Claims.Clone() 工作,u.Claims 必须是可序列化的,但不是由于上述原因.

in order for the u.Claims.Clone() to work, u.Claims must be serializable but it's not for the reasons cited above.

* 更新 III *

好的,我改变了方法,像这样实现构造函数:

ok, I changed approach, implementing the constructor like this:

public partial class Employer
{
    public Employer(User u)
    {
        this.Id = u.Id;
        this.GivenName = u.GivenName;
        this.Surname = u.Surname;

        ICollection<Claim> cs = new List<Claim>();
        foreach (Claim c in u.Claims)
        {
            cs.Add(c.Clone());
        }
        this.Claims = cs;

现在它通过了 clone() 的检查(上面的if"行),但现在它在:

and now it gets past the clone()'s check ("if" line above), but now it breaks at:

formatter.Serialize(stream, source);

与:

System.Runtime.Serialization.SerializationException was unhandled by user code
  Message=Type 'System.Data.Entity.DynamicProxies.User_7B7AFFFE306AB2E39C07D91CC157792F503F36DFCAB490FB3333A52EA1D5DC0D' in Assembly 'EntityFrameworkDynamicProxies-Web, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' is not marked as serializable.
  Source=mscorlib
  StackTrace:
       at System.Runtime.Serialization.FormatterServices.InternalGetSerializableMembers(RuntimeType type)
       at System.Runtime.Serialization.FormatterServices.GetSerializableMembers(Type type, StreamingContext context)
       at System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.InitMemberInfo()
       at System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.InitSerialize(Object obj, ISurrogateSelector surrogateSelector, StreamingContext context, SerObjectInfoInit serObjectInfoInit, IFormatterConverter converter, ObjectWriter objectWriter, SerializationBinder binder)
       at System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Write(WriteObjectInfo objectInfo, NameInfo memberNameInfo, NameInfo typeNameInfo)
       at System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Serialize(Object graph, Header[] inHeaders, __BinaryWriter serWriter, Boolean fCheck)
       at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize(Stream serializationStream, Object graph, Header[] headers, Boolean fCheck)
       at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize(Stream serializationStream, Object graph)
       at Skillscore.Web.Cloner.Clone[T](T source) in C:Users.DocumentsVisual Studio 2010Projects.WebsiteExtensions.Object.cs:line 62
       at Skillscore.Web.Models.Employer..ctor(User u) in C:Users.DocumentsVisual Studio 2010Projects.WebsiteModelsEF.Custom.cs:line 130

叹息……一切总是那么难吗?

sigh... is everything always so hard?

* 更新 IV *

好的,所以上面的问题是 Claim 类有一个指向 User 的导航器 - 这解释了为什么上面的方法将类型指示为 .User_[...] 并暗示我不仅需要使向下依赖项可序列化,而且还需要备份所有路径!但是,完成后我成功克隆了该对象,但现在我又回到了原始帖子中的问题:

ok, so the problem above is that the Claim class has a navigator that points back to User - which explains why the above method indicates the type to be .User_[...] and implies I need to not only make the downward dependencies serializable, but also all of the paths back up! However, having done that I successfully clone the object but I'm now back to the issue in my original posting:

System.InvalidOperationException was unhandled by user code
  Message=Conflicting changes to the role 'User' of the relationship 'EF.ClaimUser' have been detected.
  Source=System.Data.Entity
  StackTrace:
       at System.Data.Objects.DataClasses.RelatedEnd.IncludeEntity(IEntityWrapper wrappedEntity, Boolean addRelationshipAsUnchanged, Boolean doAttach)
       at System.Data.Objects.DataClasses.EntityCollection`1.Include(Boolean addRelationshipAsUnchanged, Boolean doAttach)
       at System.Data.Objects.DataClasses.RelationshipManager.AddRelatedEntitiesToObjectStateManager(Boolean doAttach)
       at System.Data.Objects.ObjectContext.AddObject(String entitySetName, Object entity)
       at System.Data.Entity.Internal.Linq.InternalSet`1.<>c__DisplayClass5.<Add>b__4()
       at System.Data.Entity.Internal.Linq.InternalSet`1.ActOnSet(Action action, EntityState newState, Object entity, String methodName)
       at System.Data.Entity.Internal.Linq.InternalSet`1.Add(Object entity)
       at System.Data.Entity.DbSet`1.Add(TEntity entity)
       at Skillscore.Web.Controllers.AuthController.Register(String Company, String GivenName, String Surname, String Title, String Department) in C:Users.DocumentsVisual Studio 2010Projects.WebsiteControllersAuthController.cs:line 138

人.我需要在头上打个洞.

man. I need a hole in the head.

* 更新 V *

我不知道是代理的问题还是延迟加载的问题,但仔细想想,如果我通过序列化进行克隆,所有过去属于旧对象的事物的ID现在将属于新的.我确实先在旧对象上执行了 .remove() ,如果这立即生效,那么跟踪中可能有一些不知道的东西.如果没有,那么在某一时刻会有两件事具有相同的 ID...所以我开始倾向于@Jockey 的想法,即使用对象初始值设定项进行克隆...

I don't know if the issue is the proxies or lazy loading, but after thinking about it a little, it seems that if I do a clone via serialisation, all the IDs for things that used to belong to the old object are now going to belong to the new one. I did do a .remove() first on the old object and if that has immediate effect then maybe there's something in the tracking that doesn't know about it. If it doesn't, then at one point there will be two things out there with the same ID... so I'm starting to lean towards @Jockey's idea of using object initialisers for the cloning...

推荐答案

如果您想序列化实体,您可以在检索该对象之前禁用代理创建.如果您还想序列化它们,您还需要预先加载导航属性.

If you want to serialize entities you can disable proxy creation before retrieving that object. You also need to eager load navigational properties if you want to serialize them as well.

在 EF 4.1 中禁用代理创建

To disable proxy creation in EF 4.1

dbContext.Configuration.ProxyCreationEnabled = false;

在 EF 4

objectContext.ContextOptions.ProxyCreationEnabled = false;

例如:

var users = context.Users.Include("Claims").Where(/**/);

这篇关于EF 中的可序列化类和动态代理 - 如何?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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