Entity Framework Core 2.0中的更改跟踪改变了我的代码行为

时间:2018-01-06 13:49:33

标签: c# entity-framework-core

该代码在Entity Framework 1.0中运行良好也可以是1.1。

var pupilFound = await context.Pupils.SingleOrDefaultAsync(p => p.Id == pupil.Id);
if (pupilFound == null)
{
    throw new BadDataException($"{nameof(pupil.Id)} is not valid");
}
if (pupilFound.UserId != userId)
{
    throw new NotAuthorizedException();
}

pupil.UserId = userId;
context.Entry(pupil).State = EntityState.Modified;
await contextSaveChangesAsync();

现在有了Entity Framework Core 2.0,我得到了一个错误:

Cannot be tracked because another instance of this type with the same key is already being tracked

快速解决方法是:

var pupilFound = await context.Pupils.AsNoTracking.SingleOrDefaultAsync(p => p.Id == pupil.Id);

这种方式跟踪被禁用,但这违背了关于官方推荐的AsNoTracking方法的目的:

https://docs.microsoft.com/en-us/dotnet/api/microsoft.entityframeworkcore.changetracking.changetracker.querytrackingbehavior?view=efcore-2.0

Disabling change tracking is useful for read-only scenarios because it avoids
        //     the overhead of setting up change tracking for each entity instance. You should
        //     not disable change tracking if you want to manipulate entity instances and persist
        //     those changes to the database using Microsoft.EntityFrameworkCore.DbContext.SaveChanges

如何更新学生的所有属性来自客户?

1 个答案:

答案 0 :(得分:0)

正如评论中所说的那样,这个代码在以前的测试中运行的可能性非常小。" beta" EF-core的版本(即< v.2)。他们是马车,但坏。

无论如何,你在那里做了很多可能不那么礼仪的事。

首先,应该通过应用filters在处理管道中更早地处理与授权相关的任何事情,因此您不必一次又一次地编写此重复代码。但这是一个偏离主题的地方。 (假设你在ASP.Net工作)。

其次,在主题上,你真的不需要检查数据库中是否存在id。只需将pupil对象附加为已修改并保存更改即可。无论如何你必须捕获异常,所以为什么不专门捕捉DbUpdateException,当同时删除学生时(以及其他可能的原因),这将被抛出。