Возник вопрос.
Во время добавления элемента (объекта) в БД всё работает и отображается как положено.
Но как только возникает необходимость удалить элемент из БД.
Возникает следующая ошибка:
InvalidOperationException: The instance of entity type 'UserRole' cannot be tracked because another instance with the same key value for {'RoleId', 'UserId'} is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached. Consider using 'DbContextOptionsBuilder.EnableSensitiveDataLogging' to see the conflicting key values.
Интерфейс пользователя выглядит следующим образом:
Фрагмент проблемного кода представлен ниже:
[Authorize(Roles = "Admin, SuperAdmin")]
public IActionResult Index()
{
var result = (from user in db.Users
from userRole in user.UserRoles
where userRole.Role.UserRole == UserRole.User
orderby user.FullName ascending
select user);
List<Person> persons = new List<Person>();
//Проставить всех пользователей в checked, если у них есть роль UserRole.ProjectMgr
foreach (User user in result)
{
Person p = new Person { UserId = user.UserID, FullName = user.FullName, Mail = user.Mail };
db.Entry(user).Collection(u => u.UserRoles).Query()
.Include(ur => ur.Role)
.Load();
bool @checked = user.UserRoles.Any(ur => ur.Role.UserRole == UserRole.ProjectMgr);
if (@checked)
p.Checked = @checked;
persons.Add(p);
}
return View(persons);
}
//Отметка людей как ProjectMgr
[Authorize(Roles = "Admin, SuperAdmin")]
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> SetProjectMgr(int[] checkProjectMgr)
{
//Присвоим роль пользователя при регистрации
Role role = db.Roles.FirstOrDefault(r => r.UserRole == UserRole.ProjectMgr);
foreach (User user in db.Users)
{
//Подгружаем роли пользователя
db.Entry(user).Collection(u => u.UserRoles)
.Query()
.Include(ur => ur.Role)
.Load();
//для роли пользователя
MSIE.Data.ManyToManyEntities.UserRole userRole = new Data.ManyToManyEntities.UserRole
{
Role = role,
User = user
};
//Проверяем наличие роли ProjectMgr
bool isInRole = user.UserRoles.Any(ur => ur.Role.UserRole == UserRole.ProjectMgr);
//Проверяем список пользователей для назначения им роли ProjectMgr
if (checkProjectMgr.Contains(user.UserID))
{
//Если в человека есть уже эта роль ProjectMgr, то не добавляем
//Иначе добавляем эту роль
if (isInRole)
continue;
else
{
user.UserRoles.Add(userRole);
db.UserRoles.Add(userRole);
}
}
//Убираем роль ProjectMgr, у тех пользователей, которые не отмечены
else
{
if (isInRole)
{
user.UserRoles.Remove(userRole);
db.UserRoles.Remove(userRole);
}
else
continue;
}
}
await db.SaveChangesAsync();
return RedirectToAction("Index", "Admin");
}
Детальный скрин ошибки:
Использую ASP.NET Core MVC v 2.2
В методе Index пробовал использовать AsNoTracking(), а в методе SetProjectMgr(int[] checkProjectMgr) для экземпляра userRole использовал: db.Entry(userRole).State = EntityState.Detached; и db.UserRoles.Attach(userRole); - результата никакого и проблема осталась
С чем это может быть связано?
Считаю, что это вопрос может быть полезен разработчикам работающих с EF и ASP.NET Core MVC
Спасибо за уделённое время и внимание.
Попробуй перед удалением выполнить
dbContext.ChangeTracker.Entries().ToList().ForEach(e => e.State = EntityState.Detached);
Проблема решена. Вопрос может быть закрыт. Всем спасибо за советы и участие.
Изменения коснулись метода SetProjectMgr
Этапы решения данной проблемы:
Role для пользователя User, то необходимо создать новый объект UserRole и добавить бд. UserRole.ProjectMgr, необходимо отыскать данную роль в пользователя userRole = user.UserRoles.SingleOrDefault(ur => ur.Role.UserRole == UserRole.ProjectMgr) и удалить её в db.UserRoles.Remove(userRole);.В предыдущей (старой) версии метода SetProjectMgr создавался новый объект UserRole для каждого User, следовательно при добавлении всё работало отлично.
Но, при удалении UserRole выполнялась попытка найти и удалить несуществующий (новый созданный) объект в бд, что приводило к ошибке в строке db.UserRoles.Remove(userRole);.
Также был выполнен рефакторинг кода в данном методе.
Сам код метода приведён ниже:
//Отметка людей как ProjectMgr
[Authorize(Roles = "Admin, SuperAdmin")]
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> SetProjectMgr(int[] checkProjectMgr)
{
//Присвоим роль пользователя при регистрации
Role role = db.Roles.FirstOrDefault(r => r.UserRole == UserRole.ProjectMgr);
MSIE.Data.ManyToManyEntities.UserRole userRole;
foreach (User user in db.Users)//await db.Users.ToListAsync())
{
//Подгружаем роли пользователя
db.Entry(user).Collection(u => u.UserRoles)
.Query()
.Include(ur => ur.Role)
.Load();
//Проверяем наличие роли ProjectMgr
userRole = user.UserRoles.SingleOrDefault(ur => ur.Role.UserRole == UserRole.ProjectMgr);
//Проверяем список пользователей для назначения им роли ProjectMgr
if (checkProjectMgr.Contains(user.UserID))
{
//Если в человека есть уже эта роль ProjectMgr, то не добавляем
//Иначе добавляем эту роль
if(userRole != null)
continue;
else
{
//для роли пользователя
userRole = new Data.ManyToManyEntities.UserRole
{
Role = role,
User = user
};
//user.UserRoles.Add(userRole);
db.UserRoles.Add(userRole);
}
}
//Убираем роль ProjectMgr, у тех пользователей, которые не отмечены
else
{
if (userRole != null)
{
//user.UserRoles.Remove(userRole);
db.UserRoles.Remove(userRole);
}
else
continue;
}
}
await db.SaveChangesAsync();
return RedirectToAction("Index", "Admin");
}
Продвижение своими сайтами как стратегия роста и независимости