为什么实体框架显示项目已经被跟踪,而事实上它并没有被跟踪



我有3个测试,在每个测试之间,都会创建一个新的DbContext。我检查了一下,只运行了3个测试用例,所有的测试用例都向数据库添加了相同的对象,并且没有错误。但是当我运行这个测试时:

[TestCase("test2@test.com", "test2@test.com", "123", "321", UserSaveResultStatus.UserAlreadyExists, Description = "Duplicated emails")]
[TestCase("test3@test.com", "test4@test.com", "456", "456", UserSaveResultStatus.UserWithGivenEmployeeIdAlreadyExists, Description = "Duplicated Employee Ids")]
[TestCase("test5@test.com", "test6@test.com", "", "", UserSaveResultStatus.Success, Description = "Empty Employee Ids. Should add two users")]
public void ImportUsers_Should_Add_User_Only_Once_When_Email_Or_EmployeeId_Doubled_On_The_List(string email1, string email2, string employeeId1, string employeeId2, UserSaveResultStatus expectedStatus)
{
var emails = new string[] { email1, email2 };
var employeeIds = new string[] { employeeId1, employeeId2 };
var dto = GetUserImportDto(emails, employeeIds);
var checker = dbContext.ChangeTracker
.Entries()
.Where(t => t.State == EntityState.Detached 
|| t.State == EntityState.Unchanged 
|| t.State == EntityState.Modified
|| t.State == EntityState.Detached
|| t.State == EntityState.Deleted
|| t.State == EntityState.Added);
.
.
.
Asserts

我得到这个错误:

无法跟踪实体类型"PowerPlantUser"的实例,因为已在跟踪另一个具有{'Id'}相同键值的实例。附加现有实体时,请确保仅附加一个具有给定键值的实体实例。考虑使用"DbContextOptionsBuilder.EnableSentiveDataLogging"查看冲突的键值

当抛出错误时,我在原地创建断点:

foreach (var powerPlantId in newPowerPlantsIds)
{
var personToAdd = new PowerPlantUser() { UserId = userId, PowerPlantId = powerPlantId };
var state1 = commandsContext.Entry(personToAdd).State;
var state2 = commandsContext.Entry(personToAdd).State; //STATE BEFORE ERROR IS DETACHED
commandsContext.PowerPlantUsers.Add(personToAdd); //HERE IS AN ERROR

正如我们在上面的测试中看到的,我创建了一个检查器,它显示我跟踪的条目。新的PowerPlantUser的id为0,检查程序中没有此用户。

当我单独运行测试时,没有错误,并且所有测试都通过了。有人能告诉我问题出在哪里吗?

该错误意味着DbContext已经跟踪到具有相同ID的PowerPlantUser的不同实例。它还指的是";Id";列,所以当您提供UserId和PowerPlantId时,我会检查一下您是否正在实现某个基类或定义公共";Id";没有被正确设置为标识的列,导致每个记录可能以PK"0"进入DB;0〃;。

  1. 检查PowerPlantUser定义中的Id列,以及该列是否正确设置为Identity列。(也可能取决于您用于测试的数据库。(

  2. 请检查本地跟踪缓存中是否存在匹配的实体。如果PK肯定是PowerPlantId+UserId,则添加以下代码以确认上下文是否正在跟踪现有实体:

。。

var existingItem = commandsContext.PowerPlantUsers.Local
.SingleOrDefault(x => x.PowerPlantId == powerPlantId && x.UserId == userId);

它检查跟踪缓存中的DbContext。如果它返回一个实体,那么其他东西正在DbContext中插入并留下一个被跟踪的实例。

最新更新