C# EF-how中的可序列化类和动态代理?

C# EF-how中的可序列化类和动态代理?,c#,entity-framework,asp.net-mvc-3,serialization,clone,C#,Entity Framework,Asp.net Mvc 3,Serialization,Clone,在年,我走上了克隆实体的道路。我尝试使用中的序列化方法来实现这一点 因为这些类是由Entity Framework生成的,所以我在custom.cs中单独标记它们,如下所示: [Serializable] public partial class Claims { } public partial class Employer { public Employer(User u) { this.Id = u.Id; this.GivenName =

在年,我走上了克隆实体的道路。我尝试使用中的序列化方法来实现这一点

因为这些类是由Entity Framework生成的,所以我在custom.cs中单独标记它们,如下所示:

[Serializable]
public partial class Claims
{
}
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;
但是,当检查(在克隆方法中)时:

如果被击中,我会得到错误信息:

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\.\Documents\Visual Studio 2010\Projects\.\Website\Extensions.Object.cs:line 49
       at .Web.Models.Employer..ctor(User u) in C:\Users\.\Documents\Visual Studio 2010\Projects\.\Website\Models\EF.Custom.cs:line 121
       at .Web.Controllers.AuthController.Register(String Company, String GivenName, String Surname, String Title, String Department) in C:\Users\.\Documents\Visual Studio 2010\Projects\.\Website\Controllers\AuthController.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: 
*更新II*

练习的重点是为深度拷贝提供便利。这就是它看起来的样子:

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
必须是可序列化的,但这不是出于上述原因

*更新III*

好的,我改变了方法,实现构造函数如下:

[Serializable]
public partial class Claims
{
}
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;
与:

叹息。。。一切总是那么困难吗

*更新IV*

好的,上面的问题是,
声明
类有一个指向
用户
的导航器,这解释了为什么上面的方法将类型指示为
.User_[…]
,这意味着我不仅需要使向下的依赖项可序列化,还需要备份所有路径!但是,完成此操作后,我成功克隆了对象,但现在我又回到了我最初发布的问题:

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\.\Documents\Visual Studio 2010\Projects\.\Website\Controllers\AuthController.cs:line 138
用户代码未处理System.InvalidOperationException Message=检测到对关系“EF.ClaimUser”的角色“User”的更改存在冲突。 Source=System.Data.Entity 堆栈跟踪: 位于System.Data.Objects.DataClasses.RelatedEnd.IncludeEntity(IEntityWrapper wrappedEntity、Boolean addRelationshipAsUnchanged、Boolean doAttach) 位于System.Data.Objects.DataClasses.EntityCollection`1.Include(Boolean addRelationshipAsUnchanged,Boolean doAttach) 位于System.Data.Objects.DataClasses.RelationshipManager.AddRelatedEntities到ObjectStateManager(布尔doAttach) 位于System.Data.Objects.ObjectContext.AddObject(字符串entitySetName,对象实体) 在System.Data.Entity.Internal.Linq.InternalSet`1.c__uDisplayClass5.b__uu4() 位于System.Data.Entity.Internal.Linq.InternalSet`1.ActOnSet(操作操作,EntityState新闻状态,对象实体,字符串方法名) 位于System.Data.Entity.Internal.Linq.InternalSet`1.Add(对象实体) at System.Data.Entity.DbSet`1.Add(TEntity实体) 在Skillscore.Web.Controllers.AuthController.Register(字符串公司、字符串给定名称、字符串姓氏、字符串标题、字符串部门)中的C:\Users\。\Documents\Visual Studio 2010\Projects\。\Website\Controllers\AuthController.cs:第138行 伙计。我需要在头上打个洞

*更新V*


我不知道问题是代理还是延迟加载,但仔细考虑后,似乎如果我通过序列化进行克隆,以前属于旧对象的所有ID现在都将属于新对象。我确实先对旧对象执行了
.remove()
,如果这会立即生效,那么跟踪中可能有什么东西不知道。如果没有,那么在某一点上会有两个相同ID的东西。。。所以我开始倾向于@Jockey使用对象初始化器进行克隆的想法…

查看实体框架的T4模板,您可以控制EF如何生成实体,您必须在T4模板中定义它们是可序列化的。

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

在EF 4.1中禁用代理创建

dbContext.Configuration.ProxyCreationEnabled = false;
在EF4中

objectContext.ContextOptions.ProxyCreationEnabled = false;
例如:


关闭延迟加载并关闭代理类创建。
无论如何,您仍然需要添加Serializable/DataContract属性以使其可序列化。

我在使用Entity Framework 6(EF6)时也遇到了同样的问题。我通过更改T4模板并在Using指令和Entity类开始行之间添加行[Serializable]修复了这个问题。像这样:

 <#=codeStringGenerator.UsingDirectives(inHeader: false)#>
 [Serializable]
 <#=codeStringGenerator.EntityClassOpening(entity)#>

[可序列化]

不需要其他更改。

< P>作为微软推荐,您需要使用DTO而不是EF实体来避免序列化问题,在将实体转换为DTO之前也要考虑使用急加载。

避免序列化问题的一种方法是序列化数据传输 对象(DTO)而不是实体对象

如果添加相应的导航属性[…],会发生什么情况

不幸的是,这在序列化模型时会产生问题。如果加载相关数据,它将创建一个圆形对象图

一种解决方案是使用DTO,[…]或者,您可以配置JSON和XML格式化程序来处理图形周期


这里是一个开始。骑师,谢谢你的建议。这当然很有趣,但我不知道它对我有什么帮助——请看上面我的更新。具体生成了哪个代理。如果您使用T4模板,您可以控制有关如何创建动态生成的实体的所有内容,因此您可以在该模板中定义这些代理或其他需要序列化的内容。?因此,我自己使用T4模板,使EF生成的项目可以序列化,并以POCO样式发送WCF序列化。@Jockey,是的,我明白了。问题是我不知道正确的语法来指示属性需要可序列化。。。换句话说,在进行深度复制时,我不想让
用户
可序列化,但我确实需要确保
声明
得到深度复制。我已经在上面的第二次编辑中加入了深度复制代码。用户是由EF生成的吗?是的,雇主和Claime也是。我认为答案应该是手工拖网,深度复制收藏中的元素…@Jockey,这是朝着正确的方向迈出的一步(见更新III),但唉,我不是唯一的
objectContext.ContextOptions.ProxyCreationEnabled = false;
var users = context.Users.Include("Claims").Where(/**/);
 <#=codeStringGenerator.UsingDirectives(inHeader: false)#>
 [Serializable]
 <#=codeStringGenerator.EntityClassOpening(entity)#>