简体   繁体   English

如何在服务层中使用 AsNoTracking

[英]How to use AsNoTracking in a service layer

I usually use AsNoTracking when I'm not intending to write anything.当我不打算写任何东西时,我通常使用 AsNoTracking。 How should I handle this in my service layer where dbContext is hidden behind it?我应该如何在 dbContext 隐藏在它后面的服务层中处理这个问题? (I treat EF core as repository because it is repository) (我将 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);
    }
}

Is there any better way to do this?有没有更好的方法来做到这一点?

I can also define my service as follows:我还可以如下定义我的服务:

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

What is the better way?更好的方法是什么?

Basically, it is more common problem.基本上,这是更常见的问题。

It is often happens that optimized reading methods are not convenient for updating scenarios and convenient reading methods for updating scenarios have unnecessary overhead for reading only scenarios.经常出现优化的读取方式不方便更新场景,方便的读取方式更新场景对只读场景有不必要的开销。 I see 3 options here:我在这里看到 3 个选项:

  1. Ignoring all problems with performance and just use universal GetById from your first approach for reads and updates.忽略所有性能问题,只使用第一种方法中的通用GetById进行读取和更新。 Obviously, it is applicable for simple applications and may not be applicable for high-load applications.显然,它适用于简单的应用,可能不适用于高负载的应用。
  2. Using CQRS .使用CQRS It means you will have completely separate data model for reads and updates.这意味着您将拥有完全独立的数据 model 用于读取和更新。 Since reads usually don't require the complex domain logic it allows you to use any optimizations like AsNoTracking method or even use a plain sql in repositories.由于读取通常不需要复杂的域逻辑,它允许您使用任何优化,如AsNoTracking方法,甚至在存储库中使用普通的sql It is applicable for complex apps and requires more code.它适用于复杂的应用程序并且需要更多的代码。
  3. Trying to find some compromise between these two options according to your particular needs.尝试根据您的特定需求在这两个选项之间找到一些折衷方案。

As noted in comments your SomeService looks like repository.如评论中所述,您的SomeService看起来像存储库。 Ideally, domain service should contain only business logic and shouldn't mix it with infrastructure features like AsNoTracking .理想情况下,域服务应该只包含业务逻辑,而不应该将其与AsNoTracking等基础设施功能混合。 Whereas repositories can and should contain infrastructure features like AsNoTracking , Include and etc.而存储库可以并且应该包含基础设施功能,如AsNoTrackingInclude等。

No tracking queries are useful when the results are used in a read-only scenario.当结果用于只读方案时,没有跟踪查询是有用的。 They are quicker to execute because there is no need to setup change tracking information.它们执行速度更快,因为无需设置更改跟踪信息。

You can swap an individual query to be no-tracking:您可以将单个查询交换为不跟踪:

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

You can also change the default tracking behavior at the context instance level:您还可以在上下文实例级别更改默认跟踪行为:

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

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

Ideally, you should manage the infrastructure stuff in the repository level.理想情况下,您应该在存储库级别管理基础设施。

Here is my solution.这是我的解决方案。 It works.有用。

BASE CLASS OF ALL SERVICES所有服务的基础 CLASS

public class ServicesBase
            {
                protected AppDbContext dbcontext { get; }
      
                public ServicesBase(AppDbContext dbcontext)
                {
                    this.dbcontext = dbcontext;      
                }
        
                public void AsNoTracking()
                {
                    dbcontext.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
                }
        
                public void SaveChanges()
                {
                    dbcontext.SaveChanges();
                }
        
            }

USING IN CONTROLLER在 CONTROLLER 中使用

_masterService.AsNoTracking();
var master = _masterService.GetById(1);
master.WagePerSquareMeter = 21;
_masterService.SaveChanges(); 

//or dbcontext.SaveChanges(), both of them will ot affect the database.

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM