web-dev-qa-db-fra.com

Impossible de modifier les entrées de base de données à l'aide de EFCore, EntityState.Modified: "Une opération de base de données devrait affecter une ou plusieurs lignes, mais les lignes réellement affectées."

J'utilise Identity Core 1.0 avec ASP.NET MVC Core 1.0 et Entity Framework Core 1.0 pour créer un système d'enregistrement d'utilisateur simple avec cet article comme point de départ, et j'essaie d'ajouter des rôles d'utilisateur. Je peux ajouter des rôles d'utilisateur, mais je ne peux pas les modifier. Voici l'action Edit dans la 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();
        }
    }

Voici le formulaire dans la vue correspondante:

@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" />
}

Le nouveau nom de rôle n'enregistre pas dans la base de données et j'obtiens l'exception suivante: 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. 

J'ai pu utiliser ce code exact (avec la dépendance Microsoft.AspNet.Identity.EntityFramework au lieu de EntityFrameworkCore) pour modifier les entrées de base de données à l'aide de EF 7, Identity 3, etc. 

Pourquoi ce code ne permet-il pas de modifier les entrées de la base de données?

6
jmk22

À moins d'une exception cachée qui se cache derrière cela en tant qu'exception aléatoire stupide, la raison est clairement indiquée dans l'exception.

Vérifiez la Id sur l'objet role au fur et à mesure que vous le recevez pour votre action Edit et essayez de rechercher cet identifiant dans la base de données. Le message d'exception que vous voyez indique qu'il s'attend à trouver une ligne avec un ID correspondant à l'objet que vous avez attaché, mais ce n'est pas le cas. La mise à jour échoue, car il n'a pas pu localiser une ligne correspondante pour la mettre à jour. .

EDIT:

Vous attachez l'entité deux fois, supprimez l'appel à .Attach(role) et laissez la ligne en dessous de celle-ci, ce qui est suffisant pour ajouter l'objet au contexte de suivi dans un état modifié.

//_db.Roles.Attach(role); //REMOVE THIS LINE !.
_db.Entry(role).State = Microsoft.EntityFrameworkCore.EntityState.Modified;

Attention, le fait de définir l'état de l'entrée sur modifié mettra à jour toutes les valeurs de propriété lors de l'appel de .SaveChanges(). Par conséquent, si vous souhaitez mettre à jour uniquement certaines propriétés, reportez-vous à this answer

Si cela ne résout pas votre problème, vérifiez les exceptions internes que vous avez peut-être manquées. Parfois, les messages d'exception n'ont pas de sens et masquent le problème réel que vous pourriez éventuellement trouver dans l'exception interne.

2
Siraj Mansour

Vous pouvez essayer comme indiqué ci-dessous.

[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();
    }
}

Remarque :  

Quand _db.Entry(role).State = EntityState.Modified;

  • vous attachez non seulement l'entité au _db, vous marquez également l'entité comme étant dirty.
  • Lorsque vous exécuterez _db.SaveChanges(), EF générera une instruction update Qui will update all the fields of the entity.

Quand _db.Roles.Attach(role)

  • attache l'entité au contexte sans le marquer sale .
  • C'est comme _db.Entry(role).State = EntityState.Unchanged;.
  • à moins que vous ne passiez ensuite à update a property on the entity, la prochaine fois que vous appelez context.SaveChanges(), EF ne générera pas a database update pour cette entity.

i.e. Si vous devez générer une mise à jour de la base de données, procédez comme suit:

_db.Roles.Attach(role); // State = Unchanged
role.RoleName = "Admin"; // State = Modified, and only the RoleName property is dirty
context.SaveChanges();
1
Sampath

Vos réponses ne fonctionnent pas pour moi. Et j'ai résolu mon erreur comme ceci. Modification des propriétés de la classe Model 

[Key]
    [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
    public string Id { get; set; }

après avoir changé ma classe de mapping

builder.Property(c => c.Id).HasColumnName("ID").IsRequired();

Le dernier changement est

 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;

J'espère que cette solution fonctionne pour quelqu'un.

1
Haktan Enes Biçer

Si vous avez un déclencheur INSTEAD OF INSERT sur la table, la base de données annule l'opération et EntityFramework déclenche cette erreur.

0
Sérgio Ferraz

J'ai résolu ce problème en combinant les deux méthodes

var thisRole = _db.Roles.Where(r => r.Id.Equals(role.Id, 
StringComparison.CurrentCultureIgnoreCase)).FirstOrDefault();
_db.Roles.Attach(thisRole);
thisRole.Name = role.Name;
_db.SaveChanges();
0
Minh Phuong