实体框架和RESTful WebAPI - 可能的循环引用

时间:2018-03-28 16:58:50

标签: entity-framework asp.net-web-api asp.net-web-api2 asp.net-core-webapi

以下是我的模型的简化版本:

public class User  {
    public int UserID { get; set; }
    public string FirstName { get; set; }
    public virtual ICollection<Recipe> Recipes { get; set; }
}

public class Recipe {
    public int RecipeID { get; set; }
    public string RecipeName { get; set; }
    public int UserID { get; set; }
    public virtual User User { get; set; }
}

我有一个控制器,我想返回一个用户以及一些关于他们的食谱的摘要信息。脚手架控制器代码如下所示:

var user = await _context.Users.SingleOrDefaultAsync(m => m.UserID == id);

工作正常。现在我尝试添加食谱,它打破了:

var user = await _context.Users.Include(u => u.Recipes).SingleOrDefaultAsync(m => m.UserID == id);

我的网页浏览器开始渲染JSON,它闪烁,我在浏览器中收到一条消息,说连接已经重置。

我的理论 - 我相信父(User)呈现,它暴露了包含对父(User)的引用的子(Recipe),其中包含子的集合(Recipe) )等等导致无限循环。这就是我认为这种情况发生的原因:

  1. Visual Studio调试器允许我以无限方式导航属性。
  2. 如果我注释掉Recipe.User属性,它可以正常工作。
  3. 我尝试了什么 我试图只使用实体框架投影包含来自Recipe的数据(我试图不包括Recipe.User)。我试图只包含Recipe.RecipeName ...但是当我尝试使用投影来创建这样的匿名类型时:

    var user = await _context.Users.Include(u => u.Recipes.Select(r => new { r.RecipeName })).SingleOrDefaultAsync(m => m.UserID == id);
    

    我收到此错误:

      

    InvalidOperationException:属性表达式&#39; u =&gt; {来自Recipe r in u.Recipes select new&lt;&gt; f__AnonymousType1`1(RecipeName = [r] .RecipeName)}&#39;无效。表达式应代表属性访问权限:&#39; t =&gt; t.MyProperty&#39;

    解决方案是什么?我可以用不同的语法投影吗?我是不是错了?

2 个答案:

答案 0 :(得分:0)

考虑使用POCO进行序列化而不是双重链接的实体类:

public class UserPOCO  {
    public int UserID { get; set; }
    public string FirstName { get; set; }
    public ICollection<RecipePOCO> Recipes { get; set; }
}

public class RecipePOCO {
    public int RecipeID { get; set; }
    public string RecipeName { get; set; }
    public int UserID { get; set; }
}

将实体内容复制到相应的POCO,然后将这些POCO对象作为JSON结果返回。通过使用User类删除RecipePOCO属性将删除循环引用。

答案 1 :(得分:0)

我可以为你提出3种选择。

  1. 在属性上使用ign <- sapply(file.path(tmpdir, filesvec), unlink) unlink(tmpdir, recursive=TRUE) # remove the temp dir we created ,但它会在每次使用Recipe类时都有效,所以当您想要返回Recipe类时,您将无法使用其中的用户。

    [JsonIgnore]
  2. 您可以使用此解决方案停止所有jsons https://stackoverflow.com/a/42522643/3355459
  3. 中的参考循环
  4. 最后一个选项是创建类(ViewModel),该类只包含要发送到浏览器的属性,并将结果映射到它。出于安全原因,这是最好的。