C# AsNoTracking在ASP.Net核心文档中的使用

C# AsNoTracking在ASP.Net核心文档中的使用,c#,entity-framework,entity-framework-core,C#,Entity Framework,Entity Framework Core,在ASP.Net核心文档的以下代码中编辑实体时,我一直在尝试理解AsNoTracking的用法,发现: 公共异步任务OnPostAsync(int-id) { 如果(!ModelState.IsValid) { 返回页(); } //从数据库获取联系人以获取所有者ID。 var contact=等待上下文 .Contact.AsNoTracking() .FirstOrDefaultAsync(m=>m.ContactId==id); if(contact==null) { 返回NotFound

在ASP.Net核心文档的以下代码中编辑实体时,我一直在尝试理解AsNoTracking的用法,发现:

公共异步任务OnPostAsync(int-id)
{
如果(!ModelState.IsValid)
{
返回页();
}
//从数据库获取联系人以获取所有者ID。
var contact=等待上下文
.Contact.AsNoTracking()
.FirstOrDefaultAsync(m=>m.ContactId==id);
if(contact==null)
{
返回NotFound();
}
var isAuthorized=await AuthorizationService.authorizationAsync(
用户,联系人,
联系操作(更新);
如果(!isAuthorized.Successed)
{
返回新的ChallengeResult();
}
Contact.OwnerID=Contact.OwnerID;
Context.Attach(Contact.State=EntityState.Modified;
…
wait Context.saveChangesSync();
返回页首(“/索引”);
}
AsNoTracking的摘要说明:

禁用更改跟踪对于只读方案很有用,因为它 避免为每个实体设置更改跟踪的开销 例如。如果需要,不应禁用更改跟踪 操作实体实例并将这些更改持久化到数据库 使用Microsoft.EntityFrameworkCore.DbContext.SaveChanges

很明显,这不是只读方案,运行此方法的唯一原因是尝试更新数据库中的实体


有没有解释为什么这段代码似乎与AsNoTracking摘要中给出的建议背道而驰?

事实是,
AsNoTracking()
用于获取
联系人
实例,这也是联系人重新连接到
上下文
且其
状态
设置为
实体状态的原因。
上下文
不会跟踪修改后的
-as
联系人
,您需要明确地让
上下文
知道此实体已被修改

如果未使用
AsNoTracking()
,则不需要这样做

(MS文档)

通常,在只读场景中(的R部分),您会受益于
AsNoTracking()

至于在代码片段中使用
AsNoTracking()
的潜在意图,@Panagiotis Kanavos的重点是:

“我想我理解这里的“聪明之处”-如果更新未经授权,则在不跟踪的情况下加载联系人以减少开销。如果是,则重新连接对象并尝试批准。根据该状态,其最终状态将更新并最终保存。”


没有很好的理由这样做,因为代码最终会重新附加相同的实体。很多不好的可能性:缺乏知识,货物崇拜编程,复制/粘贴编程。试图通过使用“性能”黑客来掩盖糟糕的性能。我希望有一个好的理由,因为这些是Microsoft官方文档,我希望它们提供最佳实践。这是指向Github示例的链接,而不是ASP.NET文档。这就是说,你会发现文档中的几个例子太聪明了——它们试图同时显示多个内容,最终掩盖了它们想要显示的内容。我想我理解这里的“聪明”——如果未授权更新,则在没有跟踪的情况下加载联系人,以减少开销。如果是,将重新附着对象,并尝试
批准
。根据该状态,其最终状态将更新并最终保存。微观优化和缺乏适当的注释使这一切成为一个相当令人困惑的例子OP问为什么首先使用
AsNoTracking()
,坦率地说,我看不到使用
AsNoTracking
的好理由,尤其不是在教程中。啊,是的,你是对的-我刚刚读了你关于“聪明”的评论这是一个非常复杂的例子。
public async Task<IActionResult> OnPostAsync(int id)
{
    if (!ModelState.IsValid)
    {
        return Page();
    }

    // Fetch Contact from DB to get OwnerID.
    var contact = await Context
        .Contact.AsNoTracking()
        .FirstOrDefaultAsync(m => m.ContactId == id);

    if (contact == null)
    {
        return NotFound();
    }

    var isAuthorized = await AuthorizationService.AuthorizeAsync(
                                             User, contact,
                                             ContactOperations.Update);
    if (!isAuthorized.Succeeded)
    {
        return new ChallengeResult();
    }

    Contact.OwnerID = contact.OwnerID;

    Context.Attach(Contact).State = EntityState.Modified;

    …

    await Context.SaveChangesAsync();

    return RedirectToPage("./Index");
}