如何在服务层

时间:2018-05-17 08:34:04

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

当我不打算写任何东西时,我通常会使用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);
    }
}

更好的方法是什么?

2 个答案:

答案 0 :(得分:1)

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

通常情况下,优化的阅读方法不便于更新场景,而更新场景的方便阅读方法对于只读场景具有不必要的开销。我在这里看到3个选项:

  1. 忽略性能方面的所有问题,只需使用第一种方法中的通用GetById进行读取和更新。显然,它适用于简单的应用,可能不适用于高负载应用。
  2. 使用CQRS。这意味着您将拥有完全独立的读取和更新数据模型。由于读取通常不需要复杂的域逻辑,因此它允许您使用任何优化,如AsNoTracking方法,甚至可以在存储库中使用普通sql。它适用于复杂的应用程序,需要更多代码。
  3. 根据您的特殊需求,尝试在这两个选项之间找到一些妥协。
  4. 如评论中所述,您的SomeService看起来像存储库。理想情况下,域服务应仅包含业务逻辑,不应将其与AsNoTracking等基础结构功能混合使用。而存储库可以而且应该包含AsNoTrackingInclude等基础设施功能。

答案 1 :(得分:0)

在只读方案中使用结果时,没有跟踪查询很有用。由于不需要设置更改跟踪信息,因此执行起来更快。

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

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();
}

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