1

简短的问题:如何在不使用结果的情况下显式调用 getter 并防止编译器优化删除调用。

对我想做的事情的更长解释

我正在使用带有 web api 的实体框架来构建一个简单的 rest api。我正在使用代理的延迟加载来实现一对多的关系。

现在在 DELETE-Request 上,我想删除包括所有子实体的实体(这很好用)。然后我想返回已删除的实体,包括孩子。这将失败,因为在 DELETE 之后的序列化期间延迟加载子项显然不起作用。

    [HttpDelete("{id}")]
    public RolloutPlan Delete(int id)
    {
        var parent = _context.ParentEntities.Find(id);

        _context.ParentEntities.Remove(parent);
        _context.SaveChanges();

        return parent; // lazy-loading children here will fail
    }

所以我想做的是在调用 DELETE 之前为孩子显式调用 getter 以预先加载它们:

    [HttpDelete("{id}")]
    public RolloutPlan Delete(int id)
    {
        var parent = _context.ParentEntities.Find(id);
        var children = parent.Children; // lazy-load children before DELETE.


        _context.ParentEntities.Remove(parent);
        _context.SaveChanges();

        return parent;
    }

但是,这将失败,因为编译器将删除未使用的变量 children。如果我对变量 children 做一些事情,虽然它工作正常:

    [HttpDelete("{id}")]
    public RolloutPlan Delete(int id)
    {
        var parent = _context.ParentEntities.Find(id);
        var children = parent.Children; // lazy-load children before DELETE.

        // prevent the compiler from removing the call to parent.Children
        _logger.LogInformation("Children.Count:" + children.Count);

        _context.ParentEntities.Remove(parent);
        _context.SaveChanges();

        return parent; // lazy-loading children here will fail
    }

编辑:通过添加作业进行延迟加载确实有效(我的错误)

那么解决这个问题的最佳方法是什么?我想有一种聪明的方法可以在我目前不知道的实体框架中明确加载关系,这将是解决我的问题的最佳解决方案。但我也很想知道如何解决这个问题(明确地调用 getter)。

实体:

public class ParentEntity
{
    public int? Id { get; set; }
    public virtual ICollection<ChildEntity> Children { get; set; }
}

public class ChildEntity
{
    public int Id { get; set; }
}
4

2 回答 2

2

使用 Include 进行 Eager Loading

[HttpDelete("{id}")]
[MethodImpl(MethodImplOptions.NoOptimization)]
public RolloutPlan Delete(int id)
{
    var parent = _context.ParentEntities.Include(x => x.Children ).FirstOrDefault(id)

    // lazy-load steps
    // compiler optimization needs to be turned off for this method
    // to prevent unused variable from being removed.
    var children = parent.Children;

    _context.ParentEntities.Remove(rolloutPlan);
    _context.SaveChanges();

    return rolloutPlan;
}
于 2020-01-14T08:51:58.443 回答
2

显式加载.Find().Include似乎在 EF Core 3 中不起作用。但这有效(另请参见:https ://stackoverflow.com/a/7348694/1245992 ):

    [HttpDelete("{id}")]
    public async Task<RolloutPlan> Delete(int id)
    {
        // Explicitly include children here,
        // because lazy-loading them on serialization will fail.
        var parent = await _context
            .ParentEntities
            .Include(p => p.Children)
            .SingleAsync(p => p.Id == id);

        _context.ParentEntities.Remove(parent);
        _context.SaveChanges();

        return parent;
    }
于 2020-01-14T09:21:37.180 回答