2012-07-10 2 views
2

프록시 처리중인 클래스가 DataContractAttribute(IsReference = true)으로 장식되어있는 경우 어떻게 Entity Framework 코드 첫 번째 프록시를 직렬화 할 수 있습니까? POCO가 IsReference = true 인 경우 EF 프록시 serialize 특성

ProxyContractResolver으로 DataContractSerializer를 사용하여

, 나는 다음과 같은 얻을 :

유형 'System.Data.Entity.DynamicProxies.MyType_59A83378572C10D0B31B6892FB6C3E7428C4BA214322C7A77BD5E1EB19E529CA'에 대한 IsReference 설정이 '거짓'이지만, 상위 클래스의 동일한 설정 'My.Namespace.MyType'은 'True'입니다. 파생 된 형식은 기본 형식으로 IsReference에 대해 동일한 값을 가져야합니다.

EF 프록시 생성기가 POCO에서 필요로하는 IsReference 특성을 준수하지 않는 것으로 보입니다 (그렇지 않으면 상호 참조로 인해 스택 오버플로가 발생합니다).

이러한 상황에서 EF 프록시를 직렬화하는 메커니즘이 있습니까? 방법?

+0

Btw. 왜 당신은 기업을 대리 했습니까? 일반적으로 엔터티를 serialize 할 때 동적 프록시를 사용하지 않는 것이 좋습니다. –

+0

아마 내가 잘못 이해 했겠지만, 처음로드 된 컨텍스트에서 분리하여 캐시로 직렬화 한 다음 나중에 다른 컨텍스트에 연결할 수 있기를 바란다. 시나리오는로드하는 데 비용이 많이 드는 오브젝트 그래프를 캐싱하는 것이며, 생성되는 새 오브젝트와 연관되어야합니다. MyNewObject obj = new MyNewObject() {ExpensiveToLoad = 캐시 [ "ExpensiveToLoad"]}'. –

+0

직렬화를 통해 분리하는 것은 올바른 방법이지만 여전히 프록시를 사용하는 이유를 설명하지 못합니까? 객체 그래프를 만들기 위해 느슨한로드가 필요 했습니까? –

답변

4

나는 아주 간단한 예제를 따라했는데 ProxyDataContractResolver은 예상대로 작동합니다. 사이클이있는 프록시 된 엔티티의 그래프가 올바르게 직렬화되었습니다. 모든 개체가 DataContract(IsReference=true)로 표시됩니다 -

using System; 
using System.Collections.Generic; 
using System.Data.Entity; 
using System.Data.Objects; 
using System.IO; 
using System.Linq; 
using System.Runtime.Serialization; 

namespace CFSerialization 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      using (var context = new Context()) 
      { 
       context.Database.Delete(); 
       context.Database.CreateIfNotExists(); 

       context.Masters.Add(new Master 
        { 
         Name = "abc", 
         Details = new List<Detail> 
          { 
           new Detail { Name = "a" }, 
           new Detail { Name = "b" }, 
           new Detail { Name = "c" } 
          } 
        }); 
       context.SaveChanges(); 
      } 

      using (var context = new Context()) 
      { 
       // This will get proxied Master 
       var master = context.Masters.First(); 

       var serializer = new DataContractSerializer(typeof(Master), new DataContractSerializerSettings() 
        { 
         DataContractResolver = new ProxyDataContractResolver() 
        }); 

       using (var stream = new MemoryStream()) 
       { 
        // This will also lazy load all details 
        serializer.WriteObject(stream, master); 
        stream.Seek(0, SeekOrigin.Begin); 
        var newMaster = (Master)serializer.ReadObject(stream); 
       } 
      } 
     } 
    } 

    [DataContract(IsReference=true)] 
    public class Master 
    { 
     [DataMember] 
     public int Id { get; set; } 
     [DataMember] 
     public string Name { get; set; } 
     [DataMember] 
     public virtual ICollection<Detail> Details { get; set; } 
    } 

    [DataContract(IsReference=true)] 
    public class Detail 
    { 
     [DataMember] 
     public int Id { get; set; } 
     [DataMember] 
     public string Name { get; set; } 
     [DataMember] 
     public virtual Master Master { get; set; } 
    } 

    public class Context : DbContext 
    { 
     public DbSet<Master> Masters { get; set; } 
    } 
} 

는 기능을 깰 모델의 더 복잡한 무언가가 있어야한다?

참고 : .NET 4.5에서 테스트했습니다.

+0

예, 모두 'IsReference = true'로 표시되어 있습니다. 그들은 그 속성과 공통 기본 클래스를 공유합니다. 아직 .NET 4.5를 사용하고 있지 않습니다. 아마도 그 차이가있을 것입니다. –

+0

.NET 4.0에서 다른 방법이 있습니까? –

+0

@LeoLuis : .NET 4.0에서 작동합니다. –

1

프록시 된 클래스가 IsReference=true을 직접 지정하는 경우 ProxyDataContractResolver()을 사용하는 것이 작동합니다.
위의 첫 번째 주석에서 설명한대로 기본 클래스에서 완료되면 현재 작동하지 않습니다.

관련 문제