【问题标题】:How to use AsNoTracking in a service layer如何在服务层中使用 AsNoTracking
【发布时间】:2019-08-14 02:24:45
【问题描述】:

当我不打算写任何东西时,我通常使用 AsNoTracking。我应该如何在 dbContext 隐藏在它后面的服务层中处理这个问题? (我将 EF 核心视为存储库,因为它是存储库)

public class SomeService
{
    //...

    public SomeEntity GetById(int id)
    {
        return _dbContext.Find(id);
    }

    public SomeEntity GetReadonlyById(int id)
    {
        return _dbContext.SomeEntitities.AsNoTracking().SingleOrDefault(e => e.Id == id);
    }

    public SomeEntity Update(SomeEntity someEntity)
    {
        _dbContext.Update(someEntity);
        _dbContext.SaveChanges();
    }
}

public class SomeController
{
    private readonly SomeService _someService;

    //....

    [HttpGet("{id}")]
    public IActionResult Get(int id)
    {
        var someEntity = _someService.GetReadonlyById(id);
        if (someEntity == null)
        {
            return NotFound();
        }
        return someEntity;
    }

    [HttpPut("{id}")]
    public IActionResult Modify(int id, SomeEntity modified)
    {
        var someEntity = _someService.GetById(id);
        if (someEntity == null)
        {
            return NotFound();
        }
        someEntity.Someproperty = modified.Someproperty;
        _someService.Update(someEntity);
        return Ok(someEntity);
    }
}

有没有更好的方法来做到这一点?

我还可以如下定义我的服务:

public class SomeService
{
    //...

    public SomeEntity GetById(int id)
    {
        return _dbContext.AsNoTracking.SingleOrDefault(e => e.Id == id);
    }

    public SomeEntity Update(int id, SomeEntity someEntity)
    {
        var entity = _dbContext.SomeEntities.Find(id);
        if (entity == null)
        {
            return null;
        }
        entity.Someproperty = someEntity.Someproperty;
        _dbContext.Update(entity);
        _dbContext.SaveChanges();
        return entity;
    }
}

public class SomeController
{
    private readonly SomeService _someService;

    //....

    [HttpGet("{id}")]
    public IActionResult Get(int id)
    {
        var someEntity = _someService.GetById(id);
        if (someEntity == null)
        {
            return NotFound();
        }
        return someEntity;
    }

    [HttpPut("{id}")]
    public IActionResult Modify(int id, SomeEntity modified)
    {
        var someEntity = _someService.Update(id, modified);
        if (someEntity == null)
        {
            return NotFound();
        }
        return Ok(someEntity);
    }
}

有什么更好的方法?

【问题讨论】:

  • 我更喜欢第二种方法。如果我们不得不谈论关注分离设计,那么 Repository 应该只知道如何从上下文而不是外部层获取和更新数据。
  • @user1672994 我认为你是对的。我不需要关心如何从我的控制器更新它,因为服务会为我完成它并且实现细节是隐藏的。
  • 这让我很困惑,因为每个人的做法都不一样,而且大多数情况下实现中没有 AsNoTracking,或者只是没有人关心这个功能。
  • 即使在这里github.com/dotnet-architecture/eShopOnContainers 也没有使用它,也没有关于如何处理这个问题的任何官方建议
  • 不知何故您的 SomeService 一个存储库。有所有的并发症和缺点。

标签: c# asp.net-core domain-driven-design entity-framework-core asp.net-core-webapi


【解决方案1】:

基本上,这是更常见的问题。

经常发生优化的读取方式不方便更新场景,方便的读取方式更新场景对于只读场景有不必要的开销。我在这里看到 3 个选项:

  1. 忽略所有性能问题,只使用第一种方法中的通用GetById 进行读取和更新。显然,它适用于简单的应用程序,可能不适用于高负载的应用程序。
  2. 使用CQRS。这意味着您将拥有用于读取和更新的完全独立的数据模型。由于读取通常不需要复杂的域逻辑,它允许您使用任何优化,如 AsNoTracking 方法,甚至在存储库中使用普通的 sql。它适用于复杂的应用程序并且需要更多的代码。
  3. 尝试根据您的特定需求在这两个选项之间找到一些折衷方案。

如 cmets 中所述,您的 SomeService 看起来像存储库。理想情况下,域服务应该只包含业务逻辑,而不应该将其与AsNoTracking 等基础设施功能混合在一起。而存储库可以并且应该包含基础设施功能,如AsNoTrackingInclude 等。

【讨论】:

  • 我不能让所有方法都接受 id 并在适当的地方使用 AsNoTracking 而不是期望实例吗?
  • 例如 Update(int id, Entity entitytoupdate) 而不是 Update(Entity entitytoupdate)
  • 通常有些服务看起来像存储库,但在其之上具有 DTO 映射,因此它们非常类似于 CRUD 服务,但它们返回并接受 DTO 而不是域模型
  • 为什么不呢。就像您在第二种方法中所做的那样。它可以应用于答案中的第三个选项。
【解决方案2】:

当结果用于只读方案时,没有跟踪查询是有用的。它们执行速度更快,因为无需设置更改跟踪信息。

您可以将单个查询交换为不跟踪:

using (var context = new BloggingContext())
{
    var blogs = context.Blogs
        .AsNoTracking()
        .ToList();
}

您还可以在上下文实例级别更改默认跟踪行为:

using (var context = new BloggingContext())
{
    context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;

    var blogs = context.Blogs.ToList();
}

理想情况下,您应该在存储库级别管理基础设施。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-03-31
    • 1970-01-01
    • 2012-08-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-12
    相关资源
    最近更新 更多