Entity Framework: «L'instruction de mise à jour, d'insertion ou de suppression de magasin a affecté un nombre inattendu de lignes (0).» [fermé]

324

J'utilise Entity Framework pour remplir un contrôle de grille. Parfois, lorsque je fais des mises à jour, j'obtiens l'erreur suivante:

L'instruction de mise à jour, d'insertion ou de suppression de magasin a affecté un nombre inattendu de lignes (0). Les entités peuvent avoir été modifiées ou supprimées depuis le chargement des entités. Actualisez les entrées ObjectStateManager.

Je ne peux pas comprendre comment reproduire cela. Mais cela pourrait avoir quelque chose à voir avec la proximité des mises à jour. Quelqu'un a-t-il vu ceci ou quelqu'un sait-il à quoi fait référence le message d'erreur?

Edit: Malheureusement, je ne suis plus en mesure de reproduire le problème que je rencontrais ici, car je me suis éloigné de ce projet et je ne me souviens pas si j'ai finalement trouvé une solution, si un autre développeur l'a corrigée ou si j'y ai travaillé. Je ne peux donc accepter aucune réponse.

Strongopinions
la source
J'ai eu cette erreur avec l'introduction d'une stratégie de sécurité au niveau des lignes SQL Server qui permettait les mises à jour d'une ligne dans un état qui ne pouvait pas être lu (un prédicat FILTER exclusif avec un prédicat BLOCK permissif) . EntityFramework nécessite que la ligne mise à jour soit relue après la mise à jour, sinon elle suppose qu'il s'agissait d'une erreur de concurrence (au moins lors de l'utilisation d'une concurrence optimiste).
xr280xr
Le problème peut être une portée incorrecte pour votre stackoverflow.com DBContext/questions/49154250/… (cet exemple concerne l'identité ASPNET mais s'applique à tout contexte)
Simon_Weaver
Quel que soit le contexte de cette erreur, c'est une bonne idée de mettre un point d'arrêt partout où le contexte est instancié. Vous attendiez-vous à ce qu'il soit instancié une fois lorsque vous avez chargé une page Web, mais il atteint ce point d'arrêt 5 fois? Ensuite, vous avez probablement une condition de concurrence. Regardez Request.Uripour voir l'URL réelle de la demande. Dans mon cas, j'avais une logique de suivi qui frappait mon site et chargeait inutilement le contexte de la base de données (et le mettait parfois à jour aussi). Ainsi, la page que je déboguais avait vu ses données écrasées par une logique de code de suivi stupide.
Simon_Weaver
ajouter @ Html.AntiForgeryToken () en vue
Vikas Sharma

Réponses:

199

C'est un effet secondaire d'une fonctionnalité appelée concurrence optimiste.

Je ne sais pas à 100% comment l'activer / le désactiver dans Entity Framework mais, fondamentalement, ce qu'il vous dit, c'est qu'entre le moment où vous avez récupéré les données de la base de données et le moment où vous avez enregistré vos modifications, quelqu'un d'autre a modifié les données (ce qui signifiait quand vous êtes allé pour l'enregistrer, 0 lignes ont été mises à jour). En termes SQL, updatela whereclause de leur requête contient la valeur d'origine de chaque champ de la ligne, et si 0 ligne est affectée, elle sait que quelque chose s'est mal passé.

L'idée derrière cela est que vous ne finirez pas par écraser un changement que votre application ne savait pas s'est produit - c'est essentiellement une petite mesure de sécurité mise en place par .NET sur toutes vos mises à jour.

Si c'est cohérent, il y a des chances que cela se produise dans votre propre logique (EG: vous mettez à jour les données vous-même dans une autre méthode entre la sélection et la mise à jour), mais cela pourrait simplement être une condition de concurrence entre deux applications.

fyjham
la source
34
Cela se produit dans un environnement mono-utilisateur (sur ma machine de développement), donc je ne pense pas que cela puisse être une condition de concurrence. Je suis lié à un contrôle de grille personnalisé avec une EntityDataSource, donc je ne sais pas exactement ce qui se passe dans les coulisses, mais je n'ai pas de code supplémentaire qui modifie les tables. Existe-t-il un moyen de modifier ce paramètre de concurrence?
Strongopinions
3
Je pense que vous pouvez le faire par colonne dans votre modèle d'entité (c'est dans la fenêtre des propriétés), mais le problème est que cela vous empêchera de voir l'erreur et ne mettra toujours rien à jour. Êtes-vous en mesure d'afficher les commandes SQL allant à votre base de données (EG: SQL Server Profiler pour MSSQL)? De cette façon, vous pouvez voir quelle mise à jour elle est générée et devriez pouvoir voir pourquoi cette mise à jour n'affecte aucune ligne.
fyjham
9
Si l'entité a une propriété d'horodatage, assurez-vous de l'avoir stockée dans votre vue et assurez-vous que l'entité remplit correctement l'horodatage.
anIBMer
J'avais une colonne d'horodatage et une fois que je l'ai adressée, EF6.1 a fonctionné comme prévu, merci pour le conseil @anelBMer
JQII
3
Si vous utilisez des horodatages, l'objet que vous souhaitez supprimer nécessite l'ensemble PK et la propriété RowVersion afin de le mettre à jour avec succès! Je définissais la propriété rowVersion (horodatage), après avoir attaché l'objet au DbSet respectif, c'est pourquoi cela n'a pas fonctionné. Bon travail!
Legends
394

J'ai rencontré cela et cela était dû au fait que le champ ID (clé) de l'entité n'était pas défini. Ainsi, lorsque le contexte est allé enregistrer les données, il n'a pas pu trouver un ID = 0. Assurez-vous de placer un point d'arrêt dans votre instruction de mise à jour et vérifiez que l'ID de l'entité a été défini.

D'après le commentaire de Paul Bellora

J'ai eu ce problème exact, causé en oubliant d'inclure l'entrée d'ID masqué dans la page d'édition .cshtml

webtrifusion
la source
3
+1 J'avais le même problème et cela a aidé à trouver la solution. Il s'avère que j'avais [Bind (Exclude = "OrderID")] dans mon modèle de commande, ce qui provoquait la valeur de l'ID de l'entité à zéro sur HttpPost.
Dhaust
2
C'est exactement ce qui me manquait. L'ID de mon objet était 0.
Azhar Khorasany
4
@ Html.HiddenFor (model => model.productID) - a parfaitement fonctionné. Il me manquait le productID sur la PAGE DE MODIFICATION (MVC RAZOR)
Ravi Ram
2
J'ai eu un problème similaire mais avec une torsion. Pour moi, le problème était que je n'avais pas correctement configuré la table sql. Mon champ de clé primaire n'a pas été défini sur incrémentation automatique. Donc EF enverrait l'enregistrement que j'essayais d'insérer sans clé, ce qui est bien si vous vous souvenez de dire à sql que ce champ est un champ d'identité à incrémentation automatique, que j'ai oublié: <
Agile Noob
1
Même problème mais en utilisant une clé composite. L'une des valeurs clés n'a pas été définie.
obaylis
113

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

Pour faire court, si vous créez un nouvel objet et que vous dites à EF qu'il est modifié à l'aide de EntityState.Modifiedalors il générera 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 idiot, mais cela est dû au fait que la méthode en question lui avait été footransmise après avoir été créée plus tôt, maintenant elle ne lui est someValuepassée que et se crée fooelle-même.

Solution facile, tout changement EntityState.Modifiedde EntityState.Addedou changer cette ligne entière à:

context.MyObject.Add(foo);
Ben
la source
Merci d'avoir posté ça. C'était aussi mon problème, j'avais copié-collé du code qui définissait l'état sur EntityState.Modified.
clayRay
23

Je faisais face à cette même erreur d'effarouchement ... :) Puis j'ai réalisé que j'oubliais de définir un

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

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

Par ailleurs: HiddenForest pour ASP.NET MVC.

Leniel Maccaferri
la source
3
Cela semble être un défaut de sécurité, pour stocker le UserIdsous la forme, très sujet aux pirates informatiques ... cela devrait être rempli par la suite à partir deHttpContext.Current.User.Identity.Name
Serj Sagan
@SerjSagan vous avez raison ... mais tant que vous effectuez quelques vérifications côté serveur pour confirmer l'UserId et l'UserName actuel, vous êtes prêt à partir.
Leniel Maccaferri
1
Mon point est pourquoi même stocker cela dans le, HiddenForvous devrez l'obtenir de HttpContexttoute façon ... Je ne mettrais pas du tout cette propriété sous la forme, ce qui m'obligerait à toujours la remplir côté serveur ...
Serj Sagan
16

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

Solly
la source
+1. Solution parfaite et simple pour moi. Je lie GridView à EntityDataSource et je n'ai pas défini cela sur ma clé primaire sur l'objet.
Andez
Nous savons que l'interface utilisateur de Kendo ne prend pas en charge la clé composite, mais si j'ai ajouté une nouvelle colonne qui concaté mes clés à une, que se passe-t-il alors?
Branislav
15

Le problème est causé par l'une des deux choses suivantes: -

  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é l'enregistrement des données. C'est à dire. certains ont modifié les données de ligne entre le moment où vous avez reçu les données du serveur et le moment où vous avez enregistré vos données de serveur.
  2. Vous avez essayé de mettre à jour ou de supprimer une ligne, mais la ligne n'existe pas. Un autre exemple de quelqu'un qui modifie les données (dans ce cas, les supprime) entre une récupération puis les enregistre OU vous essayez de mettre à jour un champ qui n'est pas une identité (c.-à-d. StoreGeneratedPattern = Computed) Et cette ligne n'existe pas.
Pure.Krome
la source
1
Cela peut également être dû au fait que toutes les propriétés d'objet qui leur ont été affectées ont été affectées avec les mêmes valeurs qu'auparavant.
Serj Sagan
+1 pour le 2e. J'avais StoreGeneratedPattern = None, changer pour StoreGeneratedPattern = Identity a résolu le problème. Merci
tkt986
12

J'ai eu cette même erreur car une partie du PK était une colonne datetime et l'enregistrement inséré utilisait DateTime.Now comme valeur pour cette colonne. Le cadre d'entité insère la valeur avec une précision en millisecondes, puis recherche la valeur qu'il vient d'insérer également avec une précision en millisecondes. Cependant, SqlServer avait arrondi la valeur à la seconde précision, et donc le framework d'entité n'a pas pu trouver la valeur de précision en millisecondes.

La solution consistait à tronquer les millisecondes de DateTime.Now avant l'insertion.

innominate227
la source
2
Nous avons eu le même problème, sauf que nous insérions dans une Datecolonne avec une DateTimevaleur
adam0101
1
Pareil ici. Nous avions un enregistrement d'entrepôt de données et utilisions l'horodatage comme élément de la clé. L'horodatage dans l'entrepôt de données était un SQL DateTime, mais l'horodatage en C # ne correspondait pas. J'ai changé le type de données SQL en DateTime2 (7), mis à jour le modèle EF et tout a été corrigé.
mmcfly
Changer la colonne en Datetime2 (7) a également fonctionné pour moi. Merci @mmcfly
Dzejms
10

J'avais le même problème et la réponse de @ webtrifusion a aidé à trouver la solution.

Mon modèle utilisait l' Bind(Exclude)attribut sur l'ID de l'entité, ce qui provoquait la valeur de l'ID de l'entité à zéro sur HttpPost.

namespace OrderUp.Models
{
[Bind(Exclude = "OrderID")]
public class Order
{
    [ScaffoldColumn(false)]
    public int OrderID { get; set; }

    [ScaffoldColumn(false)]
    public System.DateTime OrderDate { get; set; }

    [Required(ErrorMessage = "Name is required")]
    public string Username { get; set; }
    }
}   
Échappement
la source
Problème similaire, pour des raisons de sécurité, j'ai Bind (include = certains champs). L'ID n'était pas dans la liste. Je l'ai également ajouté comme entrée cachée. Doit avoir effacé quelque chose généré par MVC ou l'ID n'était pas là du tout. Merci pour l'aide.
MusicAndCode
10

J'ai eu le même problème, je pense que cela a été causé par RowVersion qui était nul. Vérifiez que votre ID et votre RowVersion ne sont pas nuls .

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

Bilel Chaouadi
la source
la version en ligne était nulle dans mon cas
Prakash
Dans mon cas, j'avais accidentellement supprimé le champ Id dans mon [Bind (Include = properties)]. Ajoutez-le en arrière et cela a bien fonctionné.
Caverman
8

J'ai commencé à obtenir cette erreur après être passé du modèle en premier au code en premier. J'ai plusieurs threads mettant à 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-first, supposons qu'il utilise une valeur par défaut de concurrence différente.

Pour le gérer en un seul endroit en connaissant 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();
            }
        }
}

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

avenmore
la source
1
OK, tout le monde se plaint du problème, montrant comment il peut le déclencher, etc., mais cette réponse a une réponse intéressante. J'utilise un modèle de mise à jour continue (pas de bouton de sauvegarde ici bébé) et j'obtenais cela sur les mises à jour de la grille lorsque le thread EF était en retard, et je l'ai résolu. Un travail brillant mon bon nom .. vous m'avez fait ressembler à un héros - debout sur l'épaule des géants !!
Tony Trembath-Drake
Aidez-moi aussi, regardez ceci pour plus d'options
Zvi Redler
7

Vous devez inclure explicitement un BoundField 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 en CSS dont l'affichage est réglé sur «aucun».

Paulo
la source
1
hah, vous m'avez fait comprendre que j'ai supprimé mon champ d'ID caché dans ASP.NET MVC. Merci @Paulo! :)
Tomasz Iniewicz
7

Lors de la modification, incluez l'identifiant ou la clé primaire de l'entité en tant que champ masqué dans la vue

c'est à dire

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

qui résout le problème.

Aussi, si votre modèle comprend un élément non utilisé, incluez-le également et postez-le sur le contrôleur

Arun Aravind
la source
7

J'ai également rencontré cette erreur. Le problème s'est avéré provenir d'un déclencheur sur la table dans laquelle j'essayais d'enregistrer. Le déclencheur a utilisé 'INSTEAD OF INSERT', ce qui signifie qu'aucune ligne n'a été insérée dans cette table, d'où l'erreur. Heureusement, dans le cas où la fonctionnalité de déclenchement était incorrecte, mais je suppose que cela pourrait être une opération valide qui devrait en quelque sorte être gérée dans le code. J'espère que cela aidera quelqu'un un jour.

Péché
la source
2
L'entité peut être amenée à croire que des lignes ont été ajoutées en renvoyant une instruction SELECT (avec la colonne de clé primaire) à partir du déclencheur.
jahu
1
Pour développer le commentaire de @jahu, j'ai dû obtenir un identifiant réel de l'élément nouvellement inséré à renvoyer de mon déclencheur et le nom de la colonne doit correspondre à la colonne d'identité de la table de déclencheur (dans mon cas, en fait une vue, donc il ne l'a pas fait 'ai pas d'identité propre mais j'avais trompé l'edmx en le faisant croire). Mon déclencheur faisait une insertion dans une table séparée, alors j'ai juste ajouté cette dernière ligne à mon déclencheur:SELECT SCOPE_IDENTITY() as MyViewId
DannyMeister
Voir aussi cette question: stackoverflow.com/questions/5820992/…
J. Polfer
Dans mon cas, je faisais une opération de suppression sur les entités d'une collection enfant, mais il y avait un déclencheur lors de la suppression pour l'une des entités enfant qui avait provoqué la suppression d'une autre des entités enfant. Cela a provoqué l'erreur car N-1 lignes ont été affectées en raison du déclenchement de la suppression d'une des entités enfant elle-même avant que le framework d'entité ne tente de la supprimer.
skeletank
6

Je suis tombé sur ce problème sur une table à laquelle il 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 l'insertion, l'horodatage avait une heure plus précise (2018-03-20 08: 29: 51.8319154) qui a été tronquée à (2018-03-20 08: 29: 51.832) de sorte que la recherche sur les champs clés échoue.

combatc2
la source
5

J'ai également eu cette erreur. Dans certaines situations, l'entité peut ne pas être au courant du contexte de base de données réel que vous utilisez ou le modèle peut être différent. Pour cela, définissez: EntityState.Modified; à EntityState.Added;

Pour faire ça:

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

Cela garantira que l'entité sait que vous utilisez ou ajoutez l'État avec lequel vous travaillez. À ce stade, toutes les valeurs de modèle correctes doivent être définies. Attention à ne pas perdre les modifications qui pourraient avoir été apportées en arrière-plan.

J'espère que cela t'aides.

clou rouillé
la source
1
tu es un gourou! ses travaux pour moi!
Hernaldo Gonzalez
5
  @Html.HiddenFor(model => model.RowVersion)

Ma version de ligne était nulle, j'ai donc dû l'ajouter à la vue qui a résolu mon problème

Prakash
la source
Je ne passais pas RowVersion de la vue à l'action d'édition, et j'ai oublié de faire la liaison de modèle pour RowVersion. Au moment où vous enregistrez l'objet dans db, vous avez besoin de la valeur précédente de la soumission RowVersion à la db avec l'objet pour la vérification de concurrence. Vous faites des erreurs stupides lorsque vous avez besoin de choses plus rapidement!
Dhanuka777
5

La ligne a [DatabaseGenerated(System.ComponentModel.DataAnnotations.DatabaseGeneratedOption.None)]fait l'affaire dans mon cas:

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


[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int? SomeNumber { get; set; }
Tomo
la source
4

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

j'ai constaté que les erreurs lors de la mise à jour étaient généralement dues à: - Aucune clé primaire dans le tableau - Aucune clé primaire dans la vue / le formulaire d'édition (par exemple @Html.HiddenFor(m=>m.Id )

Moji
la source
4

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é.

ajaysinghdav10d
la source
4

J'ai eu cette erreur sporadiquement lors de l'utilisation d'un async méthode. Cela ne s'est pas produit 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();
}

Fonctionne 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();
}
Ogglas
la source
Bien que cela ait résolu mon problème, cela a permis de signaler le problème sous-jacent mentionné plus tôt dans ce post sur les versions de PKs & Row. J'avais négligé d'ajouter une carte de schéma pour une nouvelle table qui était encore compliquée par le fait que le PK n'a pas suivi la règle de convention de dénomination. ID <Nom de la table>.
midohioboarder
3

J'ai eu cette erreur lorsque je supprimais certaines lignes de la base de données (dans la boucle) et ajoutais les nouvelles dans la même table.

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

Tony
la source
J'ai dû faire la même chose, toujours pas sûr pourquoi le problème s'est produit en premier lieu, mais cela fonctionne.
Jed Grant
3
    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();
                }
        }
    }
Prem Prakash
la source
Pouvez-vous préciser à quoi «cela» fait référence ici et à quoi correspond ObjectStateManager? J'essaie ceci dans notre classe de référentiel de base mais j'obtiens des erreurs
Naomi
3

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

OU

Cela peut également se produire si toutes les propriétés d'objet qui ont été affectées à, elles ont été affectées avec les mêmes valeurs qu'auparavant.

        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
        }
Serj Sagan
la source
2

Si vous essayez de créer un mappage dans votre fichier edmx vers une "fonction Imports", cela peut entraîner cette erreur. Effacez simplement les champs d'insertion, de mise à jour et de suppression qui se trouvent dans les détails de mappage pour une entité donnée dans votre edmx, et cela devrait fonctionner. J'espère que je l'ai dit clairement.

Moubarak
la source
2

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

context.Users.Attach(orderer);

avec

if (orderer.Id > 0) {
    context.Users.Attach(orderer);
}
Andrew
la source
2

Eh bien, j'ai ce même problème. Mais cela était dû à ma propre erreur. En fait, je sauvegardais un objet au lieu de l'ajouter. C'était donc le conflit.

Ali
la source
2

Une façon de déboguer ce problème dans un environnement Sql Server est d'utiliser le Sql Profiler inclus avec votre copie de SqlServer, ou si vous utilisez la version Express, obtenez gratuitement une copie d'Express Profiler de CodePlex en suivant le lien ci-dessous:

Express Profiler

En utilisant Sql Profiler, vous pouvez accéder à tout ce qui est envoyé par EF à la base de données. Dans mon cas, cela équivalait à:

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

J'ai copié collé cela dans une fenêtre de requête dans Sql Server et l'ai exécuté. Effectivement, bien qu'elle ait fonctionné, 0 enregistrements ont été affectés par cette requête, d'où l'erreur renvoyée par EF.

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

Aucun ID de catégorie n'a été identifié par l'ID EF envoyé à la base de données, donc aucun enregistrement n'a été affecté.

Ce n'était pas la faute d'EF mais plutôt un buggy null coalescing "??" dans un contrôleur de vue qui envoyait des non-sens au niveau des données.

rism
la source
2

Aucune des réponses ci-dessus ne couvrait tout à fait ma situation et la solution.

Code où l'erreur a été lancé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 lorsque j'enregistrais un objet dans une vue d'édition. La raison pour laquelle il l'a lancé est que lorsque je suis retourné le sauvegarder, j'avais modifié les propriétés qui formaient la clé primaire de l'objet. Ainsi, définir son état sur Modifié n'avait aucun sens pour EF - c'était une nouvelle entrée, pas une entrée précédemment enregistrée.

Vous pouvez résoudre ce problème en A) modifiant l'appel de sauvegarde pour ajouter l'objet, ou B) ne modifiez simplement pas la clé primaire lors de la modification. J'ai fait B).

J. Polfer
la source
2

Lorsque la réponse acceptée a dit " cela ne finira pas par écraser un changement dont votre application ne savait pas qu'il s'était passé ", j'étais sceptique car mon objet avait été nouvellement créé. Mais il s'avère qu'il y avait une INSTEAD OF UPDATE, INSERT- TRIGGERpièce jointe à la table qui mettait à jour une colonne calculée de la même table.

Une fois que j'ai changé cela AFTER INSERT, UPDATE, cela fonctionnait bien.

Mahesh
la source
2

Cela m'est arrivé en raison d'un décalage entre datetime et datetime2. Étrangement, cela a bien fonctionné avant qu'un testeur ne découvre le problème. Mon modèle Code First incluait un DateTime dans le cadre de la clé primaire:

[Key, Column(Order = 2)]  
public DateTime PurchasedDate { get; set; } = (DateTime)SqlDateTime.MinValue;

La colonne générée est une colonne datetime. Lors de l'appel à SaveChanges, EF a généré le SQL suivant:

-- Region Parameters
DECLARE @0 Int = 2
DECLARE @1 Int = 25
DECLARE @2 Int = 141051
DECLARE @3 DateTime2 = '2017-07-27 15:16:09.2630000' --(will not equal a datetime value)
-- EndRegion
UPDATE [dbo].[OrganizationSurvey]
SET [OrganizationSurveyStatusId] = @0
WHERE ((([SurveyID] = @1) AND ([OrganizationID] = @2)) AND ([PurchasedDate] = @3))

Puisqu'il essayait de faire correspondre une colonne datetime avec une valeur datetime2, il n'a renvoyé aucun résultat. La seule solution à laquelle je pouvais penser était de changer la colonne en datetime2:

[Key, Column(Order = 2, TypeName = "DateTime2")]  
public DateTime PurchasedDate { get; set; } = (DateTime)SqlDateTime.MinValue;
R. Salisbury
la source
1
L'étrangeté de ce travail ne fonctionne pas par rapport a à voir avec le format / base du sous - jacent par datetimerapport datetime2. Essentiellement, certaines valeurs en millisecondes seront évaluées en correspondance, d'autres non. La même chose m'est arrivée et je suis également passée à DateTime2.
xr280xr
+1 J'aimerais pouvoir +100 sur celui-ci pour vous. Après avoir parcouru de nombreux endroits, j'ai finalement trouvé cela et j'ai réalisé que, en effet, j'avais un Datetime dans le cadre de ma clé primaire. Oui, cela l'a en effet corrigé. J'ai mis à jour la colonne vers Datetime2 et cela a fonctionné. Maintenant, mon boeuf est avec Entity Framework pour concevoir une telle requête merdique pour cela qui me force à le faire.
Catchops