Не удалось редактировать записи db с помощью EFCore, EntityState.Modified: "Операция базы данных должна влиять на 1 строку (строки), но на самом деле затрагивает 0 строк (строк)".
Я использую Identity Core 1.0 с ASP.NET MVC Core 1.0 и Entity Framework Core 1.0 для создания простой системы регистрации пользователей с этой статьей в качестве отправной точки, и я пытаюсь добавить роли пользователей. Я могу добавлять роли пользователей, но не могу их редактировать. Вот действие Edit
в RolesController
:
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Edit(IdentityRole role)
{
try
{
_db.Roles.Attach(role);
_db.Entry(role).State = Microsoft.EntityFrameworkCore.EntityState.Modified;
_db.SaveChanges();
return RedirectToAction("Index");
}
catch (Exception ex)
{
Console.WriteLine(ex);
return View();
}
}
Вот форма в соответствующем представлении:
@model Microsoft.AspNet.Identity.EntityFramework.IdentityRole
@{
ViewBag.Title = "Edit";
}
<h2>Edit Role</h2>
<hr />
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
@Html.ValidationSummary(true)
@Html.HiddenFor(model => model.Id)
<div>Role name</div>
<p>@Html.TextBoxFor(model => model.Name)</p>
<input type="submit" value="Save" />
}
Имя новой роли не сохраняется в базе данных, и я получаю следующее исключение: Database operation expected to affect 1 row(s) but actually affected 0 row(s). Data may have been modified or deleted since entities were loaded.
Database operation expected to affect 1 row(s) but actually affected 0 row(s). Data may have been modified or deleted since entities were loaded.
Я смог использовать этот точный код (с зависимостью Microsoft.AspNet.Identity.EntityFramework
вместо EntityFrameworkCore
) для редактирования записей базы данных с использованием EF 7, Identity 3 и т.д.
Любые мысли о том, почему этот код не позволяет изменять записи в базе данных?
Ответы
Ответ 1
Если есть скрытое исключение, которое скрывается за этим как немое случайное исключение, причина четко указывается в исключении.
Проверьте Id
на объекте role
, когда вы его получите в своем действии Edit
, и попробуйте найти этот идентификатор в базе данных. Сообщение о исключении, которое вы видите, указывает, что оно ожидает найти строку с соответствующим идентификатором объекта, который вы подключили, но это не так, поэтому он не выполняет обновление, так как не смог найти подходящую строку для ее обновления.
EDIT:
Вы присоединяете объект дважды, удалите вызов .Attach(role)
и держите строку под ним, что достаточно, чтобы добавить объект в контекст отслеживания в измененном состоянии.
//_db.Roles.Attach(role); //REMOVE THIS LINE !.
_db.Entry(role).State = Microsoft.EntityFrameworkCore.EntityState.Modified;
Остерегайтесь того, что установка состояния измененной записи обновит все значения свойств при вызове .SaveChanges()
, поэтому, если вы хотите обновить только определенные свойства, обратитесь к этому ответу.
Если это не решит вашу проблему, проверьте все внутренние исключения, которые вы, возможно, пропустили. Иногда сообщения об исключениях не имеют смысла и маскируют реальную проблему, которую вы могли бы найти во внутреннем исключении.
Ответ 2
Вы можете попробовать, как показано ниже.
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Edit(IdentityRole role)
{
try
{
_db.Entry(role).State = Microsoft.EntityFrameworkCore.EntityState.Modified;
_db.SaveChanges();
return RedirectToAction("Index");
}
catch (Exception ex)
{
Console.WriteLine(ex);
return View();
}
}
Примечание:
Когда _db.Entry(role).State = EntityState.Modified;
- вы не только присоединяете объект к
_db
, но также отмечаете
всего объекта dirty
.
- Когда вы выполняете
_db.SaveChanges()
, EF будет генерировать update
что will update all the fields of the entity
.
Когда _db.Roles.Attach(role)
- привязывает объект к контексту , не отмечая его грязным.
- Это похоже на
_db.Entry(role).State = EntityState.Unchanged;
.
- если вы не перейдете к
update a property on the entity
, при следующем вызове context.SaveChanges()
EF
не будет генерировать a database update
для этого entity
.
i.e. Если вам нужно создать обновление базы данных, вам нужно сделать следующее:
_db.Roles.Attach(role); // State = Unchanged
role.RoleName = "Admin"; // State = Modified, and only the RoleName property is dirty
context.SaveChanges();
Ответ 3
Ваши ответы не работают для меня. И я решил свою ошибку следующим образом. Изменены пропорции класса модели
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public string Id { get; set; }
после того как я изменил мой класс отображения
builder.Property(c => c.Id).HasColumnName("ID").IsRequired();
Последнее изменение
CustomerEntity thisrole = (from x in db.Customers
where x.Id == Id
select x).First();
thisrole.Id = accountNum;
thisrole.Name = name;
thisrole.Phone = phone;
thisrole.Email = email;
thisrole.Address = address;
db.SaveChanges();
return true;
Я надеюсь, что это решение работает для кого-то.
Ответ 4
После выполнения обновления или удаления EF Core считывает количество затронутых строк.
SELECT [ExampleEntityId]
FROM [ExampleEntities]
WHERE @@ROWCOUNT = 1 AND
[ExampleEntityId] = scope_identity();
Если у ваших сущностей нет первичного ключа IdentityColumn, EF Core выдает исключение DbUpdateConcurrencyException.
В моем случае я добавил первичные ключи (и установил их как идентичность) к связанным таблицам в базе данных.
Ответ 5
Я решил это, объединив два метода
var thisRole = _db.Roles.Where(r => r.Id.Equals(role.Id,
StringComparison.CurrentCultureIgnoreCase)).FirstOrDefault();
_db.Roles.Attach(thisRole);
thisRole.Name = role.Name;
_db.SaveChanges();
Ответ 6
Если в таблице есть триггер INSTEAD OF INSERT, база данных отменяет операцию, и EntityFramework запускает эту ошибку.
Ответ 7
Та же самая ошибка здесь, что закончилось тем, что проблема, я вставляю, повторно используя код для обновления...
Role role = new Role();
role.Value = input;
context.Add(role);
await context.SaveChangesAsync();
Там нет состояния, которое будет изменено при вставке...
Ответ 8
в mysql требуется идентификатор AUTO_INCREMENT
как это:
ALTER TABLE wfdbcore201test
. wftransitioninstance
MODIFY COLUMN ID
int (11) NOT NULL AUTO_INCREMENT FIRST;