【问题标题】:EF Core loading relationships when I don't want it to当我不希望它时,EF Core 加载关系
【发布时间】:2019-10-10 12:37:26
【问题描述】:

我有一个使用 EagerLoading 拉回实体的服务。 在大多数情况下,这是可行的,但我最近发现了一个问题。 我有一个字段:

public class Field
{
    [Required] public int Id { get; set; }
    [Required, MaxLength(100)] public string CategoryId { get; set; }
    [Required, MaxLength(100)] public string Name { get; set; }
    public FieldDataType DataType { get; set; }
    public bool IsSpecification { get; set; }

    public IList<FieldMap> FieldMaps { get; set; }
}

如您所见,它有一组与之关联的FieldMaps。 FieldMap 如下所示:

public class FieldMap
{
    public int Id { get; set; }
    public int FeedId { get; set; }
    public int FieldId { get; set; }
    [Required, MaxLength(100)] public string Path { get; set; }

    public Field Field { get; set; }
}

在我的 DbContext 中映射如下:

modelBuilder.Entity<Field>().HasMany(m => m.FieldMaps).WithOne().HasForeignKey(m => m.FieldId);

// Unique constraints
modelBuilder.Entity<Field>().HasIndex(m => new { m.CategoryId, m.Name, m.IsSpecification }).IsUnique();
modelBuilder.Entity<FieldMap>().HasIndex(m => new { m.FeedId, m.Path }).IsUnique();

// Disable cascade delete
modelBuilder.Entity<FieldMap>().HasOne(m => m.Field).WithMany(m => m.FieldMaps).OnDelete(DeleteBehavior.Restrict);

问题是,当我调用 List 方法时,它会永远拉回所有项目:

我的列表方法是这样的:

public IQueryable<T> List(params string[] includes)
{
    IQueryable<T> query = _dbEntitySet;

    return includes == null ? 
        query : 
        includes.Aggregate(query, (current, include) => current.Include(include));
}

我这样调用它:

[HttpGet("{id:int}/fields")]
[ProducesResponseType(typeof(List<Field>), StatusCodes.Status200OK)]
public IActionResult ListFieldMaps(int id)
{
    var feeds = _feedService.List();
    var feed = feeds.SingleOrDefault(m => m.Id.Equals(id));
    if (feed == null) return NotFound();

    var fieldMaps = _fieldMapService.List("Field");

    if (fieldMaps.Any(m => m.Field == null)) return BadRequest(Resources.NullFieldError);

    return Ok(fieldMaps.Where(m =>
        m.FeedId.Equals(id) &&
        m.Field.IsSpecification == (feed.Type == FeedType.Specification)).ToList());
}

如您所见,它应该只加载带有一个 Field 的 FieldMaps 列表,而不是之后的其余 fieldmaps。

有人可以帮我解决这个问题吗?

【问题讨论】:

    标签: entity-framework entity-framework-core eager-loading


    【解决方案1】:

    我找到了这篇文章:

    https://docs.microsoft.com/en-us/ef/core/querying/related-data#lazy-loading

    还有这个问题:

    https://github.com/aspnet/EntityFrameworkCore/issues/11564

    他们俩都可以添加这个:

    services.AddMvc()
        .AddJsonOptions(options =>
            options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);
    

    这导致我的问题得到解决。 现在,当我发出请求时,我会收到以下响应:

    [
        {
            "Id": 1,
            "FeedId": 1,
            "FieldId": 10,
            "Path": "aw_product_id",
            "Field": {
                "Id": 10,
                "CategoryId": "cameras",
                "Name": "gtin",
                "DataType": 0,
                "IsSpecification": false,
                "FieldMaps": []
            }
        }
    ]
    

    【讨论】:

      【解决方案2】:

      我的猜测是,由于 EF 导航属性修复,您会一遍又一遍地看到相同的实例。

      From the documentation:

      Entity Framework Core 将自动修复导航属性 到之前加载到上下文中的任何其他实体 实例。因此,即使您没有明确包含 导航属性,如果某些或 所有相关实体之前都已加载。

      尝试在 Visual Studio 中设置 Object Id(将变量添加到 Watch,右键单击它并选择“Make Object ID”)。这将为每个实例创建一个唯一的 ID,并告诉您是否正在加载不同的实体。

      【讨论】:

      • 是的,它肯定会这样做。如何让它停止?
      • 能解释为什么这是个问题吗?如果您在序列化时遇到问题,您可以指示序列化程序忽略此类循环(请参见此处,最后一段 link)
      • 因为它循环永远永远永远永远
      猜你喜欢
      • 1970-01-01
      • 2017-06-06
      • 2016-08-11
      • 2015-02-15
      • 1970-01-01
      • 1970-01-01
      • 2016-12-19
      • 2019-11-11
      • 2021-05-20
      相关资源
      最近更新 更多