6

Tôi đang cố gắng sắp xếp một mô hình miền và chạy vào một vấn đề mà tôi cần phải chuyển đổi proxy động thành POCO. Vấn đề mà tôi gặp phải là các tham chiếu vòng tròn tồn tại theo cách của các thuộc tính ảo trong mô hình. Mặc dù tôi đã cố gắng sử dụng [ScriptIgnore] để trình serializer không phân tích cú pháp các thuộc tính đó, nó vẫn hoạt động. Tôi tin rằng điều này là do các đối tượng là proxy động và vẫn còn một số tàn dư trong các thuộc tính khiến cho trình phân tích cú pháp nhập vào (do đó gây ra lỗi đệ quy "tham chiếu vòng tròn" - tôi đã thử giới hạn đệ quy đến 3 bước nhưng tôi đã lỗi "Đã vượt quá các bước đệ quy").Làm cách nào để chuyển đổi proxy động thành POCO?

Làm cách nào để chuyển đổi một đối tượng từ proxy động sang POCO để nó có thể được tuần tự hóa?

Chỉnh sửa: Ví dụ đơn giản

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 là một phân lớp của POCO mà chúng đại diện. Nói chung, bạn sẽ có thể tuần tự hóa chúng tốt. Bạn có thể đăng một ví dụ nhỏ nhưng đầy đủ của một lớp bạn không thể sắp xếp theo thứ tự không? –

+0

@EricJ. - Khi được xây dựng bình thường, lớp sẽ tuần tự hóa. Tôi có thể đăng một ví dụ, nhưng tôi không chắc chắn nó sẽ giúp ích gì khi chạy nó sẽ chạy tốt. Vấn đề chính là khi lớp được khởi tạo với dữ liệu từ ObjectContext. Đây là khi vẫn còn các tham chiếu bên trong các thuộc tính ảo mặc dù chúng phải rỗng vì chúng không được bao gồm trong truy vấn tới cơ sở dữ liệu. –

+1

Xem cấu trúc của lớp học mang lại cho bạn các vấn đề có thể làm sáng tỏ. –

Trả lời

3

Đây là một vấn đề được biết

Chúng tôi khắc phục một vấn đề trong ScriptIgnoreAttribute, mà đã không được tuyên truyền đến các lớp học có nguồn gốc. Vì các loại proxy POCO được tạo ra bằng cách xuất phát từ lớp POCO do người dùng cung cấp, nên JavaScriptSerializer không thể thấy các thuộc tính [ScriptIgnore] mà bạn có trong repro của mình.

Bản sửa lỗi sẽ không được bao gồm trong bản phát hành xem trước tiếp theo của .NET 4.5.

(như vậy có lẽ bạn phải đợi cho một phiên bản xem trước sau hoặc phiên bản chính thức)

http://connect.microsoft.com/VisualStudio/feedback/details/723060/ef-4-2-code-first-property-attributes-not-honoured

được cố định trong .NET 4.5

Từ các ý kiến ​​về vấn đề đó, có vẻ như bạn có thể làm việc xung quanh bằng cách sử dụng NonSerializedAttribute thay vì ScriptIgnoreAttribute nếu bạn đang sử dụng phiên bản hiện tại của JSON.Net

+0

"Trong khi với điều này ScriptIgnore hoặc JsonIgnore thuộc tính cuối cùng được vinh danh, nghiêm trọng này làm tê liệt Entity Framework và buộc bạn phải làm ống nước nhiều hơn bình thường - và làm như vậy đi ngược lại nguyên tắc của EF IMHO." Từ cách giải quyết. Tôi đánh giá cao liên kết và đã thấy các đề xuất để tắt tính năng này, nhưng điều đó có nghĩa là bao gồm các trường trong mọi truy vấn tôi chạy dựa vào cơ sở dữ liệu và tôi sẽ phải tìm cách khác vì điều đó. –

+0

Có nhưng cách giải quyết mà tôi nghĩ đã được viết trước khi Microsoft tiếp tục trả lời vé. MSFT trên thực tế cung cấp các giải pháp tốt hơn so với chỉ định trong cách giải quyết. Nếu bạn thay đổi 'ScriptIgnore' thành' NonSerialized' và có một phiên bản gần đây của JSON.Net, tôi tin rằng điều này sẽ làm việc ngày hôm nay. –

+0

NonSerialized không hoạt động cho mặt ảo, buồn. Tuy nhiên, khuôn mặt hạnh phúc lớn, kích hoạt cách giải quyết trên cơ sở tình huống dường như hoạt động. Tôi đang làm điều này khi một lá cờ được gửi: 'context.Configuration.ProxyCreationEnabled = false; context.Configuration.LazyLoadingEnabled = false; 'Tôi đang đánh dấu câu trả lời này là câu trả lời chính xác vì nó chỉ đến giải pháp này. –

3

Travis , Tôi biết bạn có câu trả lời được chấp nhận của bạn ở đây, nhưng muốn vượt qua một chút suy nghĩ bên về điều này. Tôi đã phải đối mặt với một vấn đề rất tương tự gần đây và không thể có được bất cứ điều gì để làm việc cho tôi, đã thử tất cả các thành phần [scriptignore], v.v.

Điều cuối cùng đã làm cho tôi là sử dụng Automapper và tạo bản đồ từ đối tượng proxy để một đối tượng poco mỏng xuống. Điều này giải quyết tất cả các vấn đề của tôi trong vòng 2 phút. Tất cả điều này sau một 36 giờ bao vây mentallity đã chiếm ưu thế khi cố gắng để có được các proxy để chơi bóng -shish :-)

Một cách tiếp cận để suy nghĩ về trong thời gian này.

[Chỉnh sửa] - sử dụng Automapper (đây là một chút automapper ứng dụng thử nghiệm tham khảo)

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

NuGet: Cài đặt-Package AutoMapper

Lớp học:

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; } 
} 

mã kiểm tra kiểm tra:

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); 
} 

cung cấp cho một thử này và xem làm thế nào bạn nhận được trên, chắc chắn nó làm việc cho tôi, 'đất' chuyển :)

+0

Bạn có thể mở rộng trên Automapper một chút không? Có lẽ với một ví dụ đơn giản?Cũng cần lưu ý, việc thay đổi cấu hình ngữ cảnh như được ghi trong câu trả lời được chấp nhận sẽ khiến thẻ '[ScriptIgnore]' được xử lý đúng cách. –

+0

chắc chắn, automapper là 'viên đạn bạc' cho nhiều vấn đề, tôi không thể vượt qua thực tế này. automapper hoạt động bằng cách cho phép bạn tạo một bản đồ giữa đối tượng vô hình phức tạp và một đối tượng thân thiện với db/serialization đơn giản hơn. tôi sẽ cập nhật câu trả lời của tôi với một ví dụ dựa trên những thứ tôi đã làm việc trên (thường là phức tạp viewModels-> poco). gimme 30 phút hoặc lâu hơn. –

+0

Điều này mang lại cho tôi ngoại lệ thời gian chạy "Thiếu cấu hình bản đồ loại hoặc bản đồ không được hỗ trợ. Các loại ánh xạ: ->" với EF 5 và AutoMapper 2.2. –

4

Để thay thế cho giải pháp Automapper Jim, tôi đã có một số thành công với 'Lập bản đồ' (sao chép nông) proxy POCO đến một thể hiện của cùng một POCO. Cách đơn giản để làm điều này là để thay đổi tập tin mẫu mà tạo ra các POCO để bao gồm một phương pháp ToSerializable(), vì vậy các lớp POCO trông như thế này:

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, 
      }; 
     } 
    } 

Dưới đây là các chức năng tôi đã thêm vào mẫu POCO (tt) nộp để tạo ra các chức năng ToSerializable (một cú pháp xấu xí như vậy.):

<#+ 
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#>, 
<#+ 
    } 
#> 
    }; 
} 
<#+ 
} 
#> 

Đó không phải là hoàn hảo, vì bạn cần phải nhớ để trở foo.ToSerializable() chứ không phải là bản thân foo bất cứ khi nào bạn mong đợi một kết quả để được tuần tự hóa, nhưng tôi hy vọng nó hữu ích cho ai đó.

+0

Cảm ơn bạn đã trả lời @daveharnett. Tuy nhiên, những gì tôi đã làm là viết phiên bản JavaScriptSerializer tùy chỉnh của riêng tôi. –

Các vấn đề liên quan