2014-01-16 55 views
0

我正在使用實體框架(代碼優先),並且映射了所有實體並禁用了延遲加載。 這工作正常,但只要我嘗試做一些Ajax工作我開始得到問題。檢測到自我引用循環EF/Json

第一個問題是我的用戶類。這看起來是這樣的:

public partial class User : IdentityUser 
{ 
    public string CompanyId { get; set; } 
    public string CreatedById { get; set; } 
    public string ModifiedById { get; set; } 
    public System.DateTime DateCreated { get; set; } 
    public Nullable<System.DateTime> DateModified { get; set; } 
    public System.DateTime LastLoginDate { get; set; } 
    public string Title { get; set; } 
    public string Forename { get; set; } 
    public string Surname { get; set; } 
    public string Email { get; set; } 
    public string JobTitle { get; set; } 
    public string Telephone { get; set; } 
    public string Mobile { get; set; } 
    public string Photo { get; set; } 
    public string LinkedIn { get; set; } 
    public string Twitter { get; set; } 
    public string Facebook { get; set; } 
    public string Google { get; set; } 
    public string Bio { get; set; } 
    public string CompanyName { get; set; } 
    public string CredentialId { get; set; } 
    public bool IsLockedOut { get; set; } 
    public bool IsApproved { get; set; } 
    public bool CanEditOwn { get; set; } 
    public bool CanEdit { get; set; } 
    public bool CanDownload { get; set; } 
    public bool RequiresApproval { get; set; } 
    public bool CanApprove { get; set; } 
    public bool CanSync { get; set; } 
    public bool AgreedTerms { get; set; } 
    public bool Deleted { get; set; } 

    public Company Company { get; set; } 
    public User CreatedBy { get; set; } 
    public User ModifiedBy { get; set; } 
    public ICollection<Asset> Assets { get; set; } 
    public ICollection<Category> Categories { get; set; } 
    public ICollection<Collection> Collections { get; set; } 
    public ICollection<Comment> Comments { get; set; } 
    public ICollection<LocalIntegration> LocalIntegrations { get; set; } 
    public ICollection<Page> Pages { get; set; } 
    public ICollection<Rating> Ratings { get; set; } 
    public ICollection<Theme> Themes { get; set; } 
    public ICollection<Group> MemberOf { get; set; } 
    public ICollection<Category> ForbiddenCategories { get; set; } 
    public ICollection<Page> ForbiddenPages { get; set; } 
} 

現在,因爲延遲加載是殘疾人,我使用預先加載代替,如果我看看這個,當我調用此方法:

// 
    // AJAX: /Users/Get 
    public JsonResult Get() 
    { 
     try 
     { 
      using (var uow = new UnitOfWork<SkipstoneContext>()) 
      { 
       var service = new UserService(uow, User.Identity.GetUserId(), this.CompanyId); 
       var u = service.GetAll("MemberOf"); 

       return new JsonResult { Data = new { success = true, users = u } }; // Return our users 
      } 
     } 
     catch (Exception ex) 
     { 
      return new JsonResult { Data = new { success = false, error = ex.Message } }; 
     } 
    } 

我可以清楚地看到只有成員導航屬性被填充。其餘部分與預期一致。

如果我試圖將u加到我的JsonResult,這就是問題出現的地方。 我得到的錯誤:

Self referencing loop detected for property 'CreatedBy' with type 'System.Data.Entity.DynamicProxies.User_E9B58CAAA82234358C2DE2AF8788D33803C4440F800EA8E015BE49C58B010EDF'. Path 'users[0]'.

在另一個帖子,我看了,出現這種情況是因爲Json.Net試圖序列化和填充所有導航屬性。

所以,我創建了一個新的項目,在我創建2種型號:

public class User 
{ 
    public User() 
    { 
     this.Id = Guid.NewGuid().ToString(); 
    } 

    public string Id { get; set; } 
    public string UserName { get; set; } 
    public string Email { get; set; } 
    public string CreatedById { get; set; } 

    public ICollection<Post> Posts { get; set; } 
    public User CreatedBy { get; set; } 
} 

public class Post 
{ 
    public string Id { get; set; } 
    public string Title { get; set; } 
    public string Message { get; set; } 
    public string CreatedById { get; set; } 

    public User CreatedBy { get; set; } 
} 

我預計運行,會有一個自我引用錯誤,因爲不僅不用戶有很多發佈,它也有一個用戶創建它。

因此該方法是這樣的:

public JsonResult Get() 
{ 
    try 
    { 
     var user = new User() 
     { 
      UserName = "moo", 
      Email = "[email protected]" 
     }; 

     return new JsonResult { Data = new { sucess = true, user = user } }; 
    } 
    catch (Exception ex) 
    { 
     return new JsonResult { Data = new { sucess = true, error = ex.Message } }; 
    } 
} 

再次,這是相同的(我的眼睛)到第一個項目。 無論如何,當我運行這個,項目運行良好。

有人可以向我解釋爲什麼會發生這種情況,我能做些什麼來解決它?

回答

1

我認爲您的導航性能竟標virtual,否則EF不會嘗試延遲加載他們...

就具有相同類型的嵌套對象的虛擬財產之內的導航屬性不作它自我引用。當屬性爲空,集合爲空時,或者當JSON序列化程序在遍歷所有實體的屬性後可以「找到出路」時,它不是自引用的。自我引用意味着我從用戶走到帖子,然後再回到同一用戶,再次發佈帖子,等等,無限次地。

要解決這個問題,不要試圖序列化實體。相反,先將它們轉換爲視圖模型,然後序列化視圖模型。

public class UserViewModel 
{ 
    public string Id { get; set; } 
    public string UserName { get; set; } 
    public string Email { get; set; } 
    public string CreatedById { get; set; } 
    public ICollection<PostViewModel> Posts { get; set; } 
    public string CreatedByUserName { get; set; } // end self-referencing 
} 

public class PostViewModel 
{ 
    public string Id { get; set; } 
    public string Title { get; set; } 
    public string Message { get; set; } 
    public string CreatedById { get; set; } 
    public string CreatedByUserName { get; set; } // end self-referencing 
} 

public JsonResult Get() 
{ 
    try 
    { 
     using (var uow = new UnitOfWork<SkipstoneContext>()) 
     { 
      var service = new UserService(uow, User.Identity.GetUserId(), this.CompanyId); 
      var u = service.GetAll("MemberOf"); 
      var vm = Mapper.Map<UserViewModel[]>(u); 
      return new JsonResult { Data = new { success = true, users = vm } }; // Return our users 
     } 
    } 
    catch (Exception ex) 
    { 
     return new JsonResult { Data = new { success = false, error = ex.Message } }; 
    } 
} 
+0

嘿,我想你可以使用ViewModels,但問題是你最終會爲每個實體產生一個(可能)大量的ViewModels。這並不吸引我。我通過創建我自己的JsonNetResult並將Ignore引用屬性添加到JsonSerializerSettings來解決此問題。 – r3plica