Entity Framework: "stocker la mise à jour, insérer, ou supprimer la déclaration affecte un nombre inattendu de lignes (0)." [fermé]

j'utilise Entity Framework pour alimenter un contrôle de grille. Parfois, lorsque je fais des mises à jour, je reçois l'erreur suivante:

stocker la mise à jour, l'insertion ou la suppression d'une déclaration affecte un nombre inattendu de lignes (0). Les entités peuvent avoir été modifiées ou supprimées depuis qu'elles ont été chargées. Actualiser Vousmanager entrées.

Je n'arrive pas à trouver comment reproduire ceci. Mais ça a peut-être quelque chose à voir avec la proximité ensemble-je faire les mises à jour. Quelqu'un a vu cette ou personne ne sait ce que le message d'erreur fait référence à?

Edit: malheureusement je n'ai plus la liberté de reproduire le problème que j'avais ici, parce que je me suis éloigné de ce projet et ne me souviens pas si j'ai finalement trouvé une solution, si un autre développeur l'a corrigé, ou si j'ai travaillé autour de lui. Je ne peux donc accepter aucune réponse.

280
demandé sur Alex Butenko 2009-12-03 01:06:10

30 réponses

c'est un effet secondaire d'une caractéristique appelée la concurrence optimiste.

pas sûr à 100% Comment l'activer/désactiver dans le cadre de L'entité, mais essentiellement ce qu'il vous dit est qu'entre le moment où vous avez saisi les données hors de la base de données et lorsque vous avez enregistré vos modifications quelqu'un d'autre a changé les données (ce qui signifie que lorsque vous êtes allé pour les enregistrer 0 lignes a été effectivement mis à jour). En termes de SQL, leur clause update query where contient la valeur originale de chaque champ dans la rangée, et si 0 lignes sont affectées il sait que quelque chose ne va pas.

l'idée derrière c'est que vous ne finirez pas par réécrire un changement que votre application ne savait pas s'est produit - c'est essentiellement une petite mesure de sécurité lancée par .NET sur toutes vos mises à jour.

si c'est cohérent, il y a des chances que cela se passe dans votre propre logique (par exemple: vous mettez les données à jour vous-même dans une autre méthode entre le select et la mise à jour), mais il pourrait s'agir simplement d'une condition de course entre deux applications.

178
répondu fyjham 2014-10-31 18:51:39

j'ai rencontré ceci et cela a été causé par le fait que le champ ID (clé) de l'entité n'était pas défini. Ainsi quand le contexte est allé pour sauver les données, il n'a pas pu trouver un ID = 0. Assurez-vous de placer un point de rupture dans votre déclaration de mise à jour et de vérifier que l'ID de l'entité a été défini.

du commentaire de Paul Bellora

j'ai eu ce problème précis, causé par l'oubli d'inclure L'ID caché entrée dans l' .CSHTML modifier la page

356
répondu webtrifusion 2013-11-25 08:48:04

Wow, beaucoup de réponses, mais j'ai eu cette erreur quand j'ai fait quelque chose légèrement différent que personne d'autre n'a mentionné.

pour faire court, si vous créez un nouvel objet et dites à EF qu'il a été modifié en utilisant le EntityState.Modified , alors il va jeter cette erreur car il n'existe pas encore dans la base de données. Voici mon code:

MyObject foo = new MyObject()
{
    someAttribute = someValue
};

context.Entry(foo).State = EntityState.Modified;
context.SaveChanges();

Oui, cela semble stupide, mais il s'est produit parce que la méthode en question avait l'habitude de foo passé à lui ayant été créé plus tôt, maintenant il a seulement someValue passé et crée des foo lui-même.

fixation facile, il suffit de changer EntityState.Modified en EntityState.Added ou de changer toute la ligne en:

context.MyObject.Add(foo);
92
répondu Ben 2012-10-18 12:38:40

je faisais face à cette même erreur effrayante... :) Puis j'ai réalisé que j'oubliais de mettre un

@Html.HiddenFor(model => model.UserProfile.UserId)

pour la clé primaire de l'objet mis à jour! J'ai tendance à oublier ce truc simple, mais très important!

soit dit en passant: HiddenFor est pour ASP.NET MVC.

22
répondu Leniel Maccaferri 2012-06-05 04:58:45

vérifiez si vous avez oublié l'attribut "DataKeyNames" dans GridView. c'est un must lors de la modification des données dans le GridView

http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.gridview.datakeynames.aspx

16
répondu Solly 2013-02-26 21:18:01

la question est causée par l'une ou l'autre de deux choses: -

  1. vous avez essayé de mettre à jour une ligne avec une ou plusieurs propriétés sont Concurrency Mode: Fixed .. et la concurrence optimiste a empêché les données d'être sauvées. IE. certaines changé les données de la ligne entre le moment où vous avez reçu les données du serveur et lorsque vous avez enregistré les données de votre serveur.
  2. Vous avez essayé de mettre à jour ou supprimer une ligne, mais la ligne n'existe pas. Un autre exemple de quelqu'un qui change les données (dans ce cas, Supprimer) entre deux récupérations puis enregistrer ou vous êtes à plat notre essai de mettre à jour un champ qui n'est pas une identité (c.-à-d. StoreGeneratedPattern = Computed ) et cette rangée n'existe pas.
14
répondu Pure.Krome 2011-02-17 02:27:01

j'ai eu cette même erreur parce qu'une partie du PK était une colonne datetime, et l'enregistrement étant inséré utilisé DateTime.Maintenant comme valeur pour cette colonne. Entity framework insérerait la valeur avec une précision de milliseconde, puis chercherait la valeur qu'il vient d'insérer aussi avec une précision de milliseconde. Cependant SqlServer avait arrondi la valeur à la seconde précision, et donc entity framework n'a pas pu trouver la valeur de précision milliseconde.

la solution était de tronquer les millisecondes de DateTime.Maintenant, avant d'insérer.

10
répondu innominate227 2015-12-10 21:17:21

j'ai eu le même problème, je me suis rendu compte que c'était causé par la RowVersion qui était nulle. Vérifiez que votre Id et votre RowVersion sont et non "null .

pour plus d'informations, reportez-vous à ce tutoriel

http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/handling-concurrency-with-the-entity-framework-in-an-asp-net-mvc-application

8
répondu Bilel Chaouadi 2015-11-23 14:02:35

lors de l'édition inclure l'id ou la clé primaire de l'entité comme champ caché dans la vue

ie

      @Html.HiddenFor(m => m.Id)

qui résout le problème.

aussi si votre modèle inclut l'article non utilisé, incluez-le aussi et postez-le au contrôleur

7
répondu Arun Aravind 2012-12-05 07:21:07

j'ai également rencontré cette erreur. Le problème a été causé par un déclencheur sur la table où j'essayais de sauver. Le Trigger utilisé 'au lieu D'insérer' ce qui signifie 0 lignes jamais obtenu inséré à cette table, d'où l'erreur. Heureusement dans le cas de mai la fonctionnalité de déclenchement était incorrecte, mais je suppose que ce pourrait être une opération valide qui devrait d'une certaine façon être traitée en code. Espérons que cela aide quelqu'un un jour.

7
répondu Si-N 2014-07-24 11:54:23

vous devez inclure explicitement un champ lié de la clé primaire. Si vous ne voulez pas que l'utilisateur voit la clé primaire, vous devez la Cacher via css:

    <asp:BoundField DataField="Id_primary_key" ItemStyle-CssClass="hidden" 
HeaderStyle-CssClass="hidden" />

Où "caché" est une classe css qui dispose d'un écran réglé sur "none".

6
répondu Paulo 2010-10-26 07:08:48

j'ai commencé à obtenir cette erreur après avoir changé de model-first EN code-first. J'ai plusieurs threads qui mettent à jour une base de données où certains peuvent mettre à jour la même ligne. Je ne sais pas pourquoi je n'ai pas eu de problème en utilisant model-d'abord, supposons qu'il utilise un défaut de concurrence différent.

pour le gérer en un seul endroit, sachant les conditions dans lesquelles il pourrait se produire, j'ai ajouté la surcharge suivante à ma classe DbContext:

using System.Data.Entity.Core.Objects;
using System.Data.Entity.Infrastructure;

public class MyDbContext: DbContext {
...
        public int SaveChanges(bool refreshOnConcurrencyException, RefreshMode refreshMode = RefreshMode.ClientWins) {
            try {
                return SaveChanges();
            }
            catch (DbUpdateConcurrencyException ex) {
                foreach (DbEntityEntry entry in ex.Entries) {
                    if (refreshMode == RefreshMode.ClientWins)
                        entry.OriginalValues.SetValues(entry.GetDatabaseValues());
                    else
                        entry.Reload();
                }
                return SaveChanges();
            }
        }
}

alors appelé SaveChanges(true) le cas échéant.

5
répondu avenmore 2014-12-11 14:39:07
  @Html.HiddenFor(model => model.RowVersion)

ma rowversion était nulle, donc j'ai dû ajouter ceci à la vue qui a résolu mon problème

5
répondu Prakash R 2015-02-17 08:32:35

La ligne [DatabaseGenerated(System.ComponentModel.DataAnnotations.DatabaseGeneratedOption.None)] a fait le tour de mon cas:

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;


[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int? SomeNumber { get; set; }
5
répondu Tomo 2018-01-18 15:46:31

assurez-vous que la table et le formulaire ont tous deux la clé primaire et edmx mis à jour.

j'ai trouvé que toutes les erreurs pendant la mise à jour étaient habituellement à cause de: - Pas de clé primaire dans le tableau - Pas de clé primaire dans la vue/forme D'édition (par exemple @Html.HiddenFor(m=>m.Id )

4
répondu Moji 2013-09-06 22:07:38

j'ai eu cette erreur sporadiquement en utilisant une méthode async . N'est pas arrivé depuis que je suis passé à une méthode synchrone.

erreurs sporadiques:

[Authorize(Roles = "Admin")]
[HttpDelete]
[Route("file/{id}/{customerId}/")]
public async Task<IHttpActionResult> Delete(int id, int customerId)
{
    var file = new Models.File() { Id = id, CustomerId = customerId };
    db.Files.Attach(file);
    db.Files.Remove(file);

    await db.SaveChangesAsync();

    return Ok();
}

Travaille tout le temps:

[Authorize(Roles = "Admin")]
[HttpDelete]
[Route("file/{id}/{customerId}/")]
public IHttpActionResult Delete(int id, int customerId)
{
    var file = new Models.File() { Id = id, CustomerId = customerId };
    db.Files.Attach(file);
    db.Files.Remove(file);

    db.SaveChanges();

    return Ok();
}
4
répondu Ogglas 2018-01-14 18:21:07

j'ai eu cette erreur quand j'ai supprimé quelques lignes dans le DB (dans la boucle), et l'ajout des nouvelles dans la même table.

les solutions pour moi étaient, de créer dynamiquement un nouveau contexte dans chaque itération de boucle

3
répondu Tony 2012-08-20 11:53:02
    public void Save(object entity)
    {
        using (var transaction = Connection.BeginTransaction())
        {
        try
                {
                    SaveChanges();
                    transaction.Commit();
                }
                catch (OptimisticConcurrencyException)
                {
                    if (ObjectStateManager.GetObjectStateEntry(entity).State == EntityState.Deleted || ObjectStateManager.GetObjectStateEntry(entity).State == EntityState.Modified)
                        this.Refresh(RefreshMode.StoreWins, entity);
                    else if (ObjectStateManager.GetObjectStateEntry(entity).State == EntityState.Added)
                        Detach(entity);
                    AcceptAllChanges(); 
                    transaction.Commit();
                }
        }
    }
3
répondu Prem Prakash 2012-12-16 18:26:09

j'ai eu le même problème. Dans mon cas, j'essayais de mettre à jour la clé primaire, ce qui n'est pas autorisé.

3
répondu ajaysinghdav10d 2015-08-30 07:33:45

si vous essayez de créer une correspondance dans votre fichier edmx vers une" fonction importe", cela peut entraîner cette erreur. Il suffit de supprimer les champs insert, update et delete qui se trouvent dans les détails de mappage d'une entité donnée dans votre edmx, et cela devrait fonctionner. J'espère que j'ai fait, il est clair.

2
répondu Mubarak 2011-05-20 20:34:12

j'ai aussi eu cette erreur. Il y a des situations où L'entité peut ne pas être au courant du contexte réel de la base de données que vous utilisez ou le modèle peut être différent. Pour cela, définissez: EntityState.Modifié; EntityState.Ajouté;

pour faire ceci:

if (ModelState.IsValid)
{
context.Entry(yourModelReference).State = EntityState.Added;
context.SaveChanges();
}

cela permettra de s'assurer que l'entité sait que vous utilisez ou ajoutez l'état avec lequel vous travaillez. À ce stade, toutes les valeurs correctes du modèle doivent être réglées. Attention à ne pas perdre tout changement qui peuvent avoir été effectuées en arrière-plan.

Espérons que cette aide.

2
répondu Rusty Nail 2013-09-17 10:55:51

Cela va également se produire si vous essayez d'insérer dans une unique contrainte de situation, c'est à dire si vous ne pouvez avoir qu'un seul type d'adresse par l'employeur et que vous essayez d'insérer un deuxième du même type avec le même employeur, vous obtiendrez le même problème.

ou

cela pourrait également se produire si toutes les propriétés de l'objet qui ont été attribuées, elles ont été attribuées avec les mêmes valeurs qu'avant.

        using(var db = new MyContext())
        {
            var address = db.Addresses.FirstOrDefault(x => x.Id == Id);

            address.StreetAddress = StreetAddress; // if you are assigning   
            address.City = City;                   // all of the same values
            address.State = State;                 // as they are
            address.ZipCode = ZipCode;             // in the database    

            db.SaveChanges();           // Then this will throw that exception
        }
2
répondu Serj Sagan 2013-11-29 19:56:39

J'ai le même numéro. Mais c'était à cause de ma propre erreur. En fait, je sauvais un objet au lieu de l'ajouter. C'était donc le conflit.

2
répondu Ali 2014-03-11 17:06:33

une façon de déboguer ce problème dans un environnement de Serveur Sql est d'utiliser le profileur Sql inclus avec votre copie de SqlServer, ou si vous utilisez la version Express, obtenez une copie D'Express Profiler pour free off de CodePlex par le lien suivant:

Express Profiler

en utilisant Sql Profiler vous pouvez accéder à tout ce qui est envoyé par EF à la DB. Dans mon cas, cela s'élevait à:

exec sp_executesql N'UPDATE [dbo].[Category]
SET [ParentID] = @0, [1048] = NULL, [1033] = @1, [MemberID] = @2, [AddedOn] = @3
WHERE ([CategoryID] = @4)
',N'@0 uniqueidentifier,@1 nvarchar(50),@2 uniqueidentifier,@3 datetime2(7),@4 uniqueidentifier',
@0='E060F2CA-433A-46A7-86BD-80CD165F5023',@1=N'I-Like-Noodles-Do-You',@2='EEDF2C83-2123-4B1C-BF8D-BE2D2FA26D09',
@3='2014-01-29 15:30:27.0435565',@4='3410FD1E-1C76-4D71-B08E-73849838F778'
go

Je l'ai copié collé dans une fenêtre de requête dans Sql Server et l'ai exécuté. Bien sûr, bien qu'il ait couru, 0 enregistrements ont été affectés par cette requête d'où L'erreur étant retournée par EF.

dans mon cas, le problème a été causé par la CategoryID.

il n'y avait pas de CategoryID identifié par L'ID EF envoyé à la base de données, donc aucun enregistrement n'a été affecté.

ce n'était pas la faute de EF mais plutôt celle d'un buggy null coalescing "??" déclaration vers le haut dans un contrôleur de vue qui envoyait des non-sens vers le bas de niveau de données.

2
répondu rism 2014-10-03 05:23:47

aucune des réponses ci-dessus n'a couvert ma situation et la solution à elle.

Code où l'erreur a été envoyée dans le contrôleur MVC5:

        if (ModelState.IsValid)
        {
            db.Entry(object).State = EntityState.Modified; 
            db.SaveChanges(); // line that threw exception
            return RedirectToAction("Index");
        }

j'ai reçu cette exception quand je sauvais un objet d'une vue D'édition. La raison pour laquelle il l'a lancé était parce que lorsque je suis retourné pour le sauver, j'avais modifié les propriétés qui formaient la clé primaire sur l'objet. Ainsi, fixer son état à Modifié n'avait aucun sens pour EF - it était un nouvelle entrée, pas sauvegardée.

vous pouvez résoudre cela en a) modifiant l'appel de sauvegarde pour ajouter l'objet, ou B) simplement ne pas changer la clé primaire sur edit. Je n'B).

2
répondu J. Polfer 2016-06-23 15:15:38

je suis tombé sur cette question sur une table qui manquait une clé primaire et avait une colonne DATETIME(2, 3) (donc la" clé primaire " de l'entité était une combinaison de toutes les colonnes)... Lors de la réalisation de l'insert, l'horodatage a eu un temps plus précis (2018-03-20 08:29:51.8319154) qui a été tronqué à (2018-03-20 08:29:51.832) de sorte que la recherche sur les champs clés échoue.

2
répondu combatc2 2018-04-02 15:44:42

j'ai trouvé ça en utilisant le RadGrid de Telerik. J'avais la clé primaire comme une colonne gridbound qui était réglée pour lire seulement. Cela fonctionnerait très bien si la colonne était display="false" mais readonly="true" a causé le problème. Je l'ai résolu en ayant la colonne gridbound display=false et en ajoutant une colonne Modèle séparée pour l'affichage

<telerik:GridBoundColumn HeaderText="Shouldnt see" Display="false" 
     UniqueName="Id" DataField="Id">
</telerik:GridBoundColumn>
<telerik:GridTemplateColumn HeaderText="Id" UniqueName="IdDisplay">
    <ItemTemplate>
        <asp:Label ID="IDLabel" runat="server" 
            Text='<%# Eval("Id") %>'></asp:Label>                               
    </ItemTemplate>
</telerik:GridTemplateColumn> 
1
répondu Talimite 2011-11-25 20:32:30

j'ai eu cette exception en attachant un objet qui n'existait pas dans la base de données. J'avais supposé que l'objet était chargé à partir d'un contexte séparé, mais si c'était la première fois que l'utilisateur visitait le site, l'objet était créé à partir de zéro. Nous avons des clés primaires auto-incrémentantes, donc je pourrais remplacer

context.Users.Attach(orderer);

avec

if (orderer.Id > 0) {
    context.Users.Attach(orderer);
}
1
répondu Andrew 2013-05-20 14:21:34

cela peut arriver si vous essayez de mettre à jour un enregistrement avec un Id qui n'existe pas dans la base de données.

1
répondu Thomas.Benz 2013-10-23 22:27:58