web-dev-qa-db-fra.com

System.Data.Linq.ChangeConflictException: ligne introuvable ou modifiée

J'essaie de supprimer une ligne gridview sélectionnée à l'aide de LINQ (N ° LINQDataSource).

Lorsque la sélection est modifiée, la liaison detailsview est également modifiée Je peux ajouter une nouvelle entrée à la base de données, mais lorsque j'ai ajouté ce code À un bouton de suppression dans updatePanel, une exception s'est produite:

try
{           
    var query = from i in db.QuestionModules 
                where i.QuestionModuleID == QuestionModuleID 
                select i;

    QuestionModule o = query.First();
    db.QuestionModules.DeleteOnSubmit(o);
    db.SubmitChanges();
}

C'est l'exception que je reçois:

System.Data.Linq.ChangeConflictException: Row not found or changed. at
System.Data.Linq.ChangeProcessor.SubmitChanges(ConflictMode
failureMode) at
System.Data.Linq.DataContext.SubmitChanges(ConflictMode failureMode)
at System.Data.Linq.DataContext.SubmitChanges() 

J'ai ce problème depuis environ une semaine et peu importe ce que je fais, il est toujours là, et l'enregistrement n'est pas supprimé.

Une idée de ce qu'il faut faire?

59
San

OK - il semble que la réponse (dans mon cas du moins) était de définir la propriété UpdateCheck de la colonne all non-clé primaire sur Jamais dans le fichier DBML. Faire cela a immédiatement résolu le problème de "Ligne non trouvée ou modifiée".

Etant donné la rumeur selon laquelle Microsoft est en train de faire taire Linq-To-Sql en faveur de Entity Framework, on peut se demander si ce type de bugs sera corrigé?

69
Mark

Vous obtenez probablement cette erreur parce que l'un de vos champs a quelque chose de différent dans le concepteur Linq To SQL et dans la base de données réelle.

Dans mon cas, c’est parce que l’un des champs était nullable dans la base de données et non nullable dans le concepteur, ce qui le rendait nullable dans le concepteur et résolvait le problème immédiatement.

51
SemMike

J'ai le même problème et je suis tombé sur ce blog , qui indique en gros que Linq-To-Sql a un problème dans sa concurrence optimiste où:

  1. Des champs datetime haute précision sont utilisés. La solution consiste à définir UpdateCheck sur Never pour cette colonne de votre fichier DBML.
  2. Les colonnes GridView définies comme invisibles accèdent à une propriété sur l'objet de données (cette deuxième raison n'a aucun sens, mais elle semble faire fureur sur ce blog).

Je n'ai pas encore essayé ces solutions, mais je reviendrai ici une fois que ce sera fait.

15
Mark

Le problème pourrait également être simplement que la définition DBML de la table n’est pas cohérente avec le statut de la définition de la base de données. Je viens de retirer le modèle DBML et de le réinsérer dans la base de données, et cela a fonctionné.

J'espère que ça aide quelqu'un.

13

J'ai résolu ce problème en veillant à actualiser mon objet immédiatement avant de le mettre à jour. Je le fais avec l'option KeepChanges.

    db.Refresh(System.Data.Linq.RefreshMode.KeepChanges, employee);
13
FranticRock

Semblait travailler pour ma situation aussi. Je construisais une ligne en mémoire, jamais soumise auparavant, qui comportait plusieurs relations de clé étrangère avec les lignes d'autres tables. InsertOnSubmit semblait fonctionner, mais un DeleteOnSubmit ultérieur me donnait l'erreur de cette ligne non trouvée. Je ne remplissais pas tous les champs de la ligne que j'ai soumise, donc je ne sais pas si cela y est pour quelque chose, mais le fait de marquer toutes les colonnes de clé non primaire de la table principale a éliminé le message d'erreur. 

Une autre pensée: je suppose que le fait de marquer la stratégie UpdateCheck d’une colonne comme «jamais» signifie qu’elle n’est pas utilisée comme base pour le contrôle de concurence optimiste. Cela impliquerait que deux utilisateurs puissent écrire sur une ligne donnée avec des données différentes dans une telle colonne et que les conflits ne soient pas détectés ... ce qui signifie que le dernier utilisateur à envoyer la ligne écraserait les valeurs de la soumission précédente. D'après diverses lectures en ligne, j'ai compris qu'une solution partielle à ce problème consiste à utiliser la méthode Refresh immédiatement avant la soumission pour synchroniser les modifications. Bien sûr, en l'absence de verrou pesimiste sur la ligne, rien ne garantit que la ligne ne sera toujours pas modifiée entre les commandes Refresh et Submit, mais dans la plupart des scénarios impliquant de grandes bases de données, cela serait rare.

Mise à jour: Après un examen approfondi, je pense avoir découvert un scénario susceptible d’affecter d’autres personnes et j’ai donc pensé que je le partagerais au cas où. Il s’avère qu’au moins une partie du problème que j’ai eu avec SQL LINQ est liée aux déclencheurs. Il semble que si vous soumettez une ligne à l'aide de SQL LINQ et que votre administrateur de base de données dispose de déclencheurs conçus pour écrire des informations dans certaines colonnes de cette ligne, le modèle SQL LINQ déterminera par défaut "Toujours" que la ligne a été modifiée depuis votre dernière écriture. . Je soumettais des lignes partiellement remplies et les déclencheurs de notre administrateur de base de données remplissent certaines colonnes. Ainsi, lorsque j'essayais de modifier davantage la ligne de notre code, il détectait un conflit de modifications basé sur les colonnes remplies par le déclencheur. J'étudie maintenant le meilleur moyen de gérer cela, mais la modification de ces champs remplis de déclencheurs pour utiliser une stratégie UpdateCheck de «Quand modifié» ou «Jamais» a fonctionné pour moi. J'espère que ça aide.

6
Travis

Ceci est juste un cas de définitions de colonne incompatibles. Supprimez simplement la table de .dbmlet rajoutez. Veillez à modifier auto generate value property = true pour les colonnes contenant des données générées automatiquement, telles que les clés primaires ou les colonnes datetime.

3
Nate S.

J'avais similaire changeconflictexception/"Ligne introuvable ou modifié" lors de la mise à jour d'une ligne . Résolu en rajoutant les onglets dans le dbml.

2
Michael9000

Le problème que j'avais était que j'avais un type DateTime dans le framework .net, mais notre champ de base de données était de type DateTime2, qui est un type de données de précision plus élevée. Ainsi, lorsque nous soumettions des modifications, les champs de date de l'objet par rapport à la base de données ne se trouvaient qu'à quelques nanosecondes, ce qui provoquerait une erreur de concurrence. Cela s'est produit lorsque nous avons migré vers une version plus récente de MSSQL et que nos champs DateTime ont été convertis en DateTime2.

Donc dans notre code où nous avions:

    Obj.DateUpdated = DateTime.Now()

Nous l'avons changé pour:

    Obj.DateUpdated = DateTime.Parse(DateTime.Now.ToString())

Vérifiez donc vos types de données, en particulier vos champs de date, si vous obtenez cette erreur après une mise à niveau et/ou une migration.

1
dherrin79

Assurez-vous qu'aucune colonne ne contient des valeurs null dans la table liée (c'est-à-dire la table à mettre à jour).

1
saltyobi

De plus, si vous appelez la méthode de sélection pour linqdatasource et définissez manuellement e.result, assurez-vous d'inclure les valeurs de clé étrangère également. 

Rien d'autre n'a fonctionné pour moi si ce n'est.

0
localman

Comme @ dherrin79 l'a indiqué, cela peut être dû à un écart de précision entre la base de données et le code. Pour moi, le problème était que la colonne de la base de données était supposée être décimale (10,2), mais elle avait été créée sous forme décimale (18,0). C'était pour un champ d'argent, alors j'aurais peut-être dû utiliser le type de colonne d'argent. 

Donc, j'ai économisé un montant en dollars, comme 3,14 $, mais la décimale a été enlevée. La valeur de la base de données a donc été modifiée et ne correspond pas à la valeur en C #.

J'espère que cela t'aides.

0
John Pasquet

Je voulais juste ajouter mon scénario à quiconque pourrait avoir ce problème.

Nous utilisons un T4 personnalisé par rapport à notre dbml Linq to SQL. En gros, nous venons de modifier le get/set de propriétés de chaîne d'origine pour couper et définir automatiquement null.

        get { return _OfficiantNameMiddle.GetValueOrNull(); }
        set 
        {
            value = value.GetValueOrNull();
            if (_OfficiantNameMiddle != value) 
            {
                _IsDirty = true;
                OnOfficiantNameMiddleChanging(value);
                SendPropertyChanging("OfficiantNameMiddle");
                _OfficiantNameMiddle = value;
                SendPropertyChanged("OfficiantNameMiddle");
                OnOfficiantNameMiddleChanged();
            }
        }

Les données héritées de notre base de données comportaient des espaces de début/fin. Par conséquent, aucune vérification de la concomitance de ces colonnes ne donnait lieu à une correspondance (la valeur ajustée était comparée à la valeur de la base non ajustée). Il était très facile de profiler SQL, de saisir le code SQL et de commencer à commenter les éléments de la clause WHERE jusqu'à ce qu'il commence à renvoyer une ligne lors de la vérification de la simultanéité.

Heureusement, nous avons un champ LastUpdatedOn dans nos tables qui est automatiquement défini via OnValidate (System.Data.Linq.ChangeAction).

    partial void OnValidate(System.Data.Linq.ChangeAction action)
    {
        if (action == System.Data.Linq.ChangeAction.Insert)
        {
            CreatedBy = CurrentUserID;
            CreatedOn = DateTime.Now;
            LastUpdatedBy = CreatedBy;
            LastUpdatedOn = CreatedOn;
        }
        else if (action == System.Data.Linq.ChangeAction.Update)
        {
            LastUpdatedBy = CurrentUserID;
            LastUpdatedOn = DateTime.Now;
        }
    }

Afin de contourner le problème, il suffit de définir la vérification de la concurrence sur Jamais sur toutes les colonnes, à l'exception des colonnes Clé primaire et LastUpdatedOn. Cela a fonctionné pour nous.

0
Jason Butera

Pour nous, le problème a commencé lorsque nous avons basculé sur DateTime2 du côté de SQL Server. Le simple fait de marquer des champs avec Column (DbType = "DateTime2") n’a pas aidé. Donc, ce qui s’est passé, c’est que, du côté de la base de données, nous avons déclaré nos colonnes comme étant DateTime2 (3) "compatibles avec l’arrière-plan" avec l’ancien type DateTime et que tout semblait bien fonctionner jusqu’à ce que nous utilisions SQL-2 -Linq nous obtenons l'exception "Ligne introuvable ou modifiée" dans les mises à jour de ces champs de date. Pour résumer l'histoire assez longue, la solution consistait à faire 2 choses:

  1. Marquez les colonnes avec [Column (DbType = "DateTime2 (3)", CanBeNull = False)] pour correspondre à la déclaration de la base de données. ET
  2. Coupez les chiffres de précision supplémentaire à partir des propriétés dans les paramètres comme ceci:

[Column(DbType = "DateTime2(3)", CanBeNull = false)] public DateTime ModifiedAt { get => _modifiedAt; set => _modifiedAt = value.AddTicks(-(value.Ticks % TimeSpan.TicksPerMillisecond)); }

0
Greg Z.

Pour moi, c’était une colonne d’énumération (mappée sur varchar) qui était à l’origine du problème; je devais donc passer le contrôle de mise à jour à jamais.

0
tec-goblin

J'ai eu un problème similaire et bien que supprimer et rajouter la table/classe DBML ait aidé certains utilisateurs, c'était pour moi un peu différent, car j'utilise WCF avec une entité détachée et un ListView sur le client.

Si j'ai utilisé le .Attache (entité), il a échoué - "Ligne non trouvée ou modifiée" Mais lorsque vous utilisez .Attache (entité, original), il fonctionne à chaque fois

public void DeleteTask(Task task)
    {
        TwoDooDataContext db = new TwoDooDataContext();
        db.Tasks.Attach(task,GetTaskByID(task.ID));
        db.Tasks.DeleteOnSubmit(task);
        db.SubmitChanges();
    }
0
Jason

J'ai pu résoudre ce problème en exécutant databind () sur gridview et datasource lors de la publication du panneau de mise à jour. 

    protected void UpdatePanel1_Load(object sender, EventArgs e)
    {
        GridView1.DataBind();
        LinqDataSource1.DataBind();
    }

J'actualise updatepanel chaque fois que mon index de sélection change et qu'il a pu résoudre les conflits.

J'espère que cela t'aides.

0
Darwin N.

La façon dont j’ai corrigé le problème était la suivante: d’abord je mets à jour la base de données, puis j’ai défini les nouvelles valeurs

e.Keys["ColumnOne"] ="new value"
e.Keys["ColumnTwo"] ="new value"

Tout cela a été fait sous l'événement GridView_RowUpdating.

0
AJ17

Sous:

QuestionModule o = query.First();

Vous devez ajouter la commande suivante:

db.QuestionModule.Attach(o);
0
suhad