6

Bir etki alanı modelini seri hale getirmeye çalışıyorum ve dinamik bir proxy'yi POCO'ya dönüştürmem gereken bir sorunla karşılaştım. İncelediğim konu, modeldeki sanal özellikler aracılığıyla dairesel referansların mevcut olduğudur. Serilaştırıcıyı bu özellikleri ayrıştırmamak için [ScriptIgnore]'u kullanmaya teşebbüs etmeme rağmen, hala geçerli. Bunun, nesnelerin dinamik proxy olduğunu ve ayrıştırıcının girmesine neden olan özelliklerde hala bazı kalıntıların olduğuna (ki bu da bir özyineleme hatası "döngüsel referansa neden olur" diye düşünürüm - yinelemeyi 3 adımla sınırlandırmayı denedim ama "Yinelemeli adımlar aşıldı" hatası.Dinamik proxy'yi POCO'ya nasıl dönüştürebilirim?

Bir nesneyi dinamik proxy'den POCO'ya nasıl dönüştürebilirim böylece serileştirilebilir?

Düzenleme: Basit bir örnek

public class One : BaseViewModel 
{ 
    public int OneId { get; set; } 
    public virtual ICollection<Two> Two { get; set; } 
} 

public class Two 
{ 
    public int TwoId { get; set; } 
    public int OneId { get; set; } 
    [ScriptIgnore] 
    public virtual One One { get; set; } 
} 

public abstract class BaseViewModel 
{ 
    public string AsJson() 
    { 
     var serializer = new JavaScriptSerializer(); 
     return serializer.Serialize(this); 
    } 
} 
+0

Proxy'ler, temsil ettikleri POCO'nun bir alt sınıfıdır. Genel olarak, bunları iyi seri hale getirebilmelisiniz. Serileştiremediğiniz bir sınıfın küçük ancak tam bir örneğini gönderir misiniz? –

+0

@EricJ. - Normal inşa edildiğinde, sınıf serileştirir. Bir örnek gönderebilirim, ancak ne kadar yardım edeceğinden emin değilim çünkü koştuğunda iyi çalışır. Asıl konu, sınıfın ObjectContext'ten veri ile eşleştirilmesidir. Sanal veritabanının içinde hala boş olsalar bile, yine de veritabanına sorguda yer almadıkları için başvurular var. –

+1

Sizi problemler veren sınıfın yapısını görmek, bir miktar ışık tutabilir. –

cevap

3

Bu Biz türetilmiş sınıflara yayılmasını değildi ScriptIgnoreAttribute bir sorunu, sabit bilinen bir sorun

olup. Kullanıcı tarafından sağlanan POCO sınıfından türetilerek POCO proxy türleri oluşturulduğundan, JavaScriptSerializer, repro'nuzdaki [ScriptIgnore] özelliklerini göremedi.

Düzeltme, .NET 4.5'in sonraki önizleme sürümüne eklenmeyecektir.

(yani muhtemelen bir alttaki önizleme sürümü veya nihai sürüm için beklemek zorunda)

.NET 4.5

o konuda yorumların itibaren düzeltilmiştir http://connect.microsoft.com/VisualStudio/feedback/details/723060/ef-4-2-code-first-property-attributes-not-honoured

, JSON.Net

+0

"Bununla birlikte ScriptIgnore veya JsonIgnore öznitelikleri nihayet onurlandırılırken, bu Cidden Entity Framework'ü ciddiye alır ve normalde sizden daha fazla su tesisatı yapmaya zorlar - ve bunu yaparken EF IMHO'nun ilkelerine aykırıdır." Geçici çözümden. Bağlantıyı takdir ediyorum ve bu özelliği devre dışı bırakmak için öneriler gördüm, ancak veritabanına karşı yürüttüğüm her sorguda alanları açıkça belirtmek anlamına geliyor ve bunun için farklı bir yol bulmak zorunda kalacağım. –

+0

Evet, ancak Microsoft'un bilete daha önce yanıt vermesinden önce yazdığım geçici çözüm geldi. MSFT, aslında, geçici çözümden daha iyi çözümler sunmuştur. ScriptIgnore'u 'NonSerialized 'olarak değiştirirseniz ve JSON.Net'in son bir sürümünü kullanıyorsanız, bunun bugün çalışacağına inanıyorum. –

+0

NonSerialized sanal ve üzgün yüz için çalışmıyor. Ancak, büyük mutlu yüz, geçici bir durum üzerinde geçici çözümü tetikliyor gibi görünüyor. Bir bayrak gönderildiğinde bunu yapıyorum: 'context.Configuration.ProxyCreationEnabled = false; context.Configuration.LazyLoadingEnabled = false; “Bu geçici çözümü işaret ettiğinden, bunu doğru yanıt olarak işaretliyorum. –

3

Travis'in geçerli sürümünü kullanıyorsanız, ScriptIgnoreAttribute yerine NonSerializedAttribute kullanarak çalışabilirsiniz gibi görünüyor Burada kabul ettiğin cevabı aldığını biliyorum, ama bunun üzerine biraz yanal düşünceyi geçmek istedim. Son zamanlarda çok benzer bir sorunla karşı karşıyaydım ve benim için çalışacak hiçbir şey alamadım, tüm [scriptignore] attibutes vb. Denedim.

Nihayet benim için çalışmış olan Automapper kullanıyor ve proxy nesnesinden bir harita oluşturuyordu zayıflanmış bir poco nesnesine. Bu, tüm sorunlarımı 2 dakika içinde çözdü. Tüm bu bir 36 saatlik kuşatma mentalitesinden sonra top oynamak için vekalet almaya çalışırken galip geldikten sonra - 0-

Arada düşünülmesi gereken başka bir yaklaşım.

[Düzenleme] - Automapper kullanılarak (bu küçük bir test uygulaması referans automapper olan)

ref: http://automapper.codeplex.com/

Nuget: yükleme Paket AutoMapper

sınıfları:

public sealed class One : BaseViewModel 
{ 
    // init collection in ctor as not using EF in test 
    // no requirement in real app 
    public One() 
    { 
     Two = new Collection<Two>(); 
    } 
    public int OneId { get; set; } 
    public ICollection<Two> Two { get; set; } 
} 

public class Two 
{ 
    public int TwoId { get; set; } 
    public int OneId { get; set; } 
    [ScriptIgnore] 
    public virtual One One { get; set; } 
} 

public abstract class BaseViewModel 
{ 
    public string AsJson() 
    { 
     var serializer = new JavaScriptSerializer(); 
     return serializer.Serialize(this); 
    } 
} 

public class OnePoco : BaseViewModel 
{ 
    public int OneId { get; set; } 
    public virtual ICollection<TwoPoco> Two { get; set; } 
} 

public class TwoPoco 
{ 
    public int TwoId { get; set; } 
    public int OneId { get; set; } 
} 

test denetleyici kodu:

public ActionResult Index() 
{ 
    // pretend this is your base proxy object 
    One oneProxy = new One { OneId = 1 }; 
    // add a few collection items 
    oneProxy.Two.Add(new Two() { OneId = 1, TwoId = 1, One = oneProxy}); 
    oneProxy.Two.Add(new Two() { OneId = 1, TwoId = 2, One = oneProxy}); 

    // create a mapping (this should go in either global.asax 
    // or in an app_start class) 
    AutoMapper.Mapper.CreateMap<One, OnePoco>(); 
    AutoMapper.Mapper.CreateMap<Two, TwoPoco>(); 

    // do the mapping- bingo, check out the asjson now 
    // i.e. oneMapped.AsJson 
    var oneMapped = AutoMapper.Mapper.Map<One, OnePoco>(oneProxy); 

    return View(oneMapped); 
} 
bu deneyin ve size nasıl çıkacağımızı, kesinlikle benim için çalıştı, 'yeryüzü' Jim'in Automapper çözümüne bir alternatif olarak :)

+0

Automapper'da biraz genişleyebilir misiniz? Belki basit bir örnekle?Ayrıca, kabul edilen cevapta belirtildiği gibi içeriğin yapılandırmasının değiştirilmesi, [ScriptIgnore] etiketlerinin düzgün bir şekilde ele alınmasına neden olacaktır. –

+0

emin, automapper birçok sorun için gümüş mermi, bu gerçeği abartmıyorum. automapper, karmaşık maddi olmayan nesne ile daha basit bir db/serileştirme dostu nesne arasında bir harita oluşturmanıza izin vererek çalışır. Cevabımı, üzerinde çalıştığım şeyler temelinde bir örnekle güncelleyeceğim (genellikle karmaşık viewModels-> poco). gimme 30 dakika ya da öylesine. –

+0

Bu bana çalışma zamanı istisnası verir "Eksik tip harita yapılandırması veya desteklenmeyen eşleme. Eşleme türleri: ->" EF 5 ve AutoMapper 2.2 ile. –

4

taşındı, ben bazı başarı elde ettik POCO proxy'sini aynı POCO'nun bir örneğine 'Eşleme' (sığ kopyalama). Bunu yapmanın basit bir yolu ToSerializable() yöntemini içerecek şekilde POCO üretir şablon dosyasını değiştirmek için, yani POCO sınıfları şu şekilde görünür: Burada

public partial class cfgCountry 
    { 
     public cfgCountry() 
     { 
      this.People = new HashSet<Person>(); 
     } 

     [Key] 
     public int CountryID { get; set; } 
     public string Name { get; set; } 
     public int Ordinal { get; set; } 

     public virtual ICollection<Person> People { get; set; } 

     public cfgCountry ToSerializable() 
     { 
      return new cfgCountry() 
      { 
      CountryID = this.CountryID, 
      Name = this.Name, 
      Ordinal = this.Ordinal, 
      }; 
     } 
    } 

ben POCO şablonuna eklediğiniz işlevi var (tt) ToSerializable fonksiyonunu oluşturmak için dosya (Bu tür çirkin bir sözdizimi.): Eğer bir sonuç bekliyoruz ne zaman yerine foo kendisinden daha) foo.ToSerializable (dönmek için hatırlamamız gerekiyor, çünkü mükemmel değil

<#+ 
void WriteToSerializableMethod (CodeGenerationTools code, IEnumerable<EdmProperty> primitiveProperties, EntityType entity) 
{ 

#> 
public <#=code.Escape(entity)#> ToSerializable() 
{ 
    return new <#=code.Escape(entity)#>() 
    { 
<#+ 
    foreach(var edmProperty in primitiveProperties) 
    { 
#> 
    <#=edmProperty.Name#> = this.<#=edmProperty.Name#>, 
<#+ 
    } 
#> 
    }; 
} 
<#+ 
} 
#> 

serileştirilmeli, ama umarım birilerine yararlı olur.

+0

Cevabınız @daveharnett için teşekkürler. Ancak, yaptığım şey kendi özel JavaScriptSerializer sürümünü yazmaktı. –

İlgili konular