lasses serializáveis e proxies dinâmicos no EF - com
Em [uma postagem anterior], Eu estava no caminho de ter que clonar minhas entidades. Eu tentei fazer isso com uma abordagem de serialização, como encontrado em [codeproject].
porque as classes são geradas pelo Entity Framework, eu as marco separadamente em um .cs personalizado como este:
[Serializable]
public partial class Claims
{
}
e qualquer maneira, quando a verificação (no método clone):
if (Object.ReferenceEquals(source, null))
{
get hit, eu recebo o erro:
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:
parentemente tão enquanto minha clasClaims
é serializável, os proxies dinâmicos gerados pela EF não são ... de alguma forma, minhas decorações não estão fluind
qual é o truque aqui?
* Atualização I *
para mais contexto: eu tenho uma classeUser
que contém uma propriedadeClaims
definido comoICollection<Claim>
. ao fazer a clonagem, o tipo que é passado é a coleção, nãoClaim
- isso explica por que o clonador está reclamando que o tipo não é serializável. então a questão agora é: como faço paraUser.Claims
serializável, pois não consigo decorar uma propriedade?
Error 1 Attribute 'Serializable' is not valid on this declaration type.
It is only valid on 'class, struct, enum, delegate' declarations.
C:\Users\.\Documents\Visual Studio 2010\Projects\.\Website\Models\EF.Custom.cs
128 10 Website
* Atualização II *
objetivo do exercício é obter uma cópia profunda. Isto é o que parece
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();
}
}
em ordem para ou.Claims.Clone()
trabalhar,u.Claims
deve ser serializável, mas não é pelos motivos citados acim
* Atualização III *
ok, mudei de abordagem, implementando o construtor assim:
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;
e agora passa a verificação do clone () ("if" acima), mas agora quebra em:
formatter.Serialize(stream, source);
com
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\.\Documents\Visual Studio 2010\Projects\.\Website\Extensions.Object.cs:line 62
at Skillscore.Web.Models.Employer..ctor(User u) in C:\Users\.\Documents\Visual Studio 2010\Projects\.\Website\Models\EF.Custom.cs:line 130
suspiro ... tudo é sempre tão difícil?
* Atualização IV *
ok, então o problema acima é que oClaim
class possui um navegador que aponta paraUser
- o que explica por que o método acima indica o tipo a ser.User_[...]
e implica que eu preciso não apenas tornar as dependências descendentes serializáveis, mas também todos os caminhos de backup! No entanto, tendo feito isso, clono o objeto com êxito, mas agora estou de volta ao problema na minha postagem original:
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
homem. Eu preciso de um buraco na cabeç
* Atualização V *
Não sei se o problema é dos proxies ou do carregamento lento, mas depois de pensar um pouco sobre isso, parece que se eu fizer um clone via serialização, todos os IDs de itens que costumavam pertencer ao objeto antigo agora estão vai pertencer ao novo. Eu fiz um.remove()
primeiro no objeto antigo e se isso tiver efeito imediato, talvez haja algo no rastreamento que não saiba sobre ele. Se isso não acontecer, em um ponto haverá duas coisas com o mesmo ID ... então estou começando a me inclinar para a idéia do @ Jockey de usar inicializadores de objetos para a clonagem ...