Не удалось редактировать записи 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;