检测到循环引用 EF 6



好的,我收到此错误:

序列化类型为"System.Data.Entity.DynamicProxies.Asset_AED71699FAD007BF6F823A5F022DB9888F62EBBD9E422BBB11D7A191CD784288"的对象时检测到循环引用。

我明白这意味着什么。我的代码是从VisualStudioTools生成的,它生成了具有虚拟导航属性的所有POCO,并映射了关系。 我对此很满意,我想要延迟加载。

这是我的用户类的示例:

public partial class User : IdentityUser
{
public User()
{
this.Assets = new List<Asset>();
this.Categories = new List<Category>();
this.Collections = new List<Collection>();
this.Comments = new List<Comment>();
this.LocalIntegrations = new List<LocalIntegration>();
this.Pages = new List<Page>();
this.Ratings = new List<Rating>();
this.Themes = new List<Theme>();
this.ForbiddenCategories = new List<Category>();
this.ForbiddenPages = new List<Page>();
}
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 virtual Company Company { get; set; }
public virtual User CreatedBy { get; set; }
public virtual User ModifiedBy { get; set; }
public virtual ICollection<Asset> Assets { get; set; }
public virtual ICollection<Category> Categories { get; set; }
public virtual ICollection<Collection> Collections { get; set; }
public virtual ICollection<Comment> Comments { get; set; }
public virtual ICollection<LocalIntegration> LocalIntegrations { get; set; }
public virtual ICollection<Page> Pages { get; set; }
public virtual ICollection<Rating> Ratings { get; set; }
public virtual ICollection<Theme> Themes { get; set; }
public virtual ICollection<Group> MemberOf { get; set; }
public virtual ICollection<Category> ForbiddenCategories { get; set; }
public virtual ICollection<Page> ForbiddenPages { get; set; }
}

我的小组课看起来像这样:

public partial class Group
{
public Group()
{
this.ForbiddenCategories = new List<Category>();
this.ForbiddenPages = new List<Page>();
this.Members = new List<User>();
}
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public string CompanyId { get; set; }
public bool Preset { get; set; }
public Nullable<bool> CanEdit { get; set; }
public Nullable<bool> CanEditOwn { get; set; }
public Nullable<bool> CanDownload { get; set; }
public Nullable<bool> RequiresApproval { get; set; }
public Nullable<bool> CanApprove { get; set; }
public System.DateTime DateCreated { get; set; }
public bool CanSync { get; set; }
public Nullable<System.DateTime> DateModified { get; set; }
public string CreatedById { get; set; }
public string ModifiedById { get; set; }
public bool Deleted { get; set; }
public virtual Company Company { get; set; }
public virtual User CreatedBy { get; set; }
public virtual User ModifiedBy { get; set; }
public virtual ICollection<Category> ForbiddenCategories { get; set; }
public virtual ICollection<Page> ForbiddenPages { get; set; }
public virtual ICollection<User> Members { get; set; }
}

我读到为了停止循环引用,你可以做这样的事情:

public async Task<JsonResult> Get()
{
try
{
using (var service = new UserService(new CompanyService()))
{
var u = from user in await service.GetAll()
select new
{
Id = user.Id,
UserName = user.UserName,
Email = user.Email,
IsApproved = user.IsApproved,
IsLockedOut = user.IsLockedOut,
MemberOf = user.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 } };
}
}

但是由于成员而返回用户时失败。 循环引用是针对用户,用户有一个集合,每个资产都有一个创建它的用户

有没有办法让它只在第一个 POCO(在本例中为User类)上进行延迟加载,以便它只加载成员、资产等,而不加载其余部分(即不是用户>资产>用户)??

更新 1

evanmcdonnal建议这可能是JsonResult的问题,而不是我的POCO类,所以我决定看看是否有办法验证这一点。 基本上,我创建了一个继承自JsonResult的JsonNetResult类,并且我覆盖了ExecuteResult这是它的样子:

public class JsonNetResult : JsonResult
{
public override void ExecuteResult(ControllerContext context)
{
if (context == null)
throw new ArgumentNullException("context");
var response = context.HttpContext.Response;
response.ContentType = !String.IsNullOrEmpty(ContentType) ? ContentType : "application/json";
if (ContentEncoding != null)
response.ContentEncoding = ContentEncoding;
if (Data == null)
return;
// If you need special handling, you can call another form of SerializeObject below
var serializedObject = JsonConvert.SerializeObject(Data, Formatting.Indented);
response.Write(serializedObject);
}
}

所以我的方法现在看起来像这样:

public async Task<JsonNetResult> Get()
{
try
{
using (var service = new UserService(new CompanyService()))
{
var u = from user in await service.GetAll()
select new
{
Id = user.Id,
UserName = user.UserName,
Email = user.Email,
IsApproved = user.IsApproved,
IsLockedOut = user.IsLockedOut,
MemberOf = user.MemberOf
};
return new JsonNetResult { Data = new { success = true, users = u } }; // Return our users
}
}
catch (Exception ex)
{
return new JsonNetResult { Data = new { success = false, error = ex.Message } };
}
}

当我运行它时,我收到与以前相同的错误,但它会显示更多详细信息。它实际上指出了这一点:

Newtonsoft.Json.Json

中发生了类型为"Newtonsoft.Json.JsonSerializationException"的异常.dll但未在用户代码中处理

其他信息:检测到类型为"System.Data.Entity.DynamicProxies.Asset_AED71699FAD007BF6F823A5F022DB9888F62EBBD9E422BBB11D7A191CD784288"的自引用循环。路径"用户[0]。成员[0]。公司资产[0].分类[0]。资产'。

现在我要检查一下是否可以更改递归限制:(

您可以尝试将 [DataContract(IsReference = true)] 添加到您的类中。这将使用引用 ID 序列化对象,并应解决循环引用问题。

根据您的更新,我将假设RecursionLimit的当前值是问题所在。该属性的文档相对稀疏,但没关系,它们可以在这里找到 http://msdn.microsoft.com/en-us/library/system.web.mvc.jsonresult.recursionlimit(v=vs.118).aspx

我相信您可以通过使用以下代码行替换当前返回行来解决此问题;

JsonResult retVal = new JsonResult();
retVal.RecursionLimit = 1000; //maybe parameteraize this?
reVal.Data = = new { success = true, users = u };
return retVal;

编辑:更新后,我知道解决问题是多么容易,因为您的异常现在由JsonConvert.SerializeObject抛出,我已经在:)之前解决了这个问题

根据您的更新,您可以通过更改ExecuteResult中的一些代码来轻松解决此问题(此选项我更有信心,因为我实际上在当前项目中实现了它,我个人没有使用过JsonResult类,我之前的建议只是我利用我对 json.NET 的一般知识)。您可以调用SerializeObject重载,如下面的示例,现在当您有循环引用时,它将抛出;

string json = JsonConvert.SerializeObject(YourInstanceToSerialize, Formatting.Indented,
new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Serialize });

ReferenceLoopHandling的可用值可以在这里找到;http://james.newtonking.com/json/help/index.html?topic=html/T_Newtonsoft_Json_ReferenceLoopHandling.htm 我相信默认值是0,这就是你的代码抛出的原因。由于您已经更新了这些更改,我想我建议您使用第二种方法(我至少知道它会起作用),但也可以随时尝试第一种方法。

我发现关闭这些查询的延迟加载是有效的。只需确保您的查询在需要时通过"包含"选择所需的所有内容。 然后在查询之前:

efContext.Configuration.LazyLoadingEnabled = false;

相关内容

  • 没有找到相关文章

最新更新