Question

Lorsque vous apportez des modifications à l'aide de SubmitChanges(), LINQ parfois meurt avec un ChangeConflictException exception avec le message d'erreur Row not found or changed, sans aucune indication de la ligne qui a le conflit ou les champs avec les changements qui sont en conflit, lorsqu'un autre utilisateur a modifié certaines données de cette ligne.

Est-il possible de déterminer la ligne qui dispose d'un conflit et les champs dans lesquels ils se produisent dans, et également est-il un moyen d'obtenir LINQ d'ignorer le problème et de simplement valider les données, peu importe?

En outre, quelqu'un sait si cette exception se produit lorsque tout données de la ligne a changé, ou seulement lorsque des données ont été modifiées dans un domaine que LINQ est de tenter de modifier?

Était-ce utile?

La solution

Voici une façon de voir où les conflits sont (c'est à MSDN exemple, de sorte que vous aurez besoin de personnaliser fortement):

try
{
    db.SubmitChanges(ConflictMode.ContinueOnConflict);
}
catch (ChangeConflictException e)
{
    Console.WriteLine("Optimistic concurrency error.");
    Console.WriteLine(e.Message);
    Console.ReadLine();
    foreach (ObjectChangeConflict occ in db.ChangeConflicts)
    {
        MetaTable metatable = db.Mapping.GetTable(occ.Object.GetType());
        Customer entityInConflict = (Customer)occ.Object;
        Console.WriteLine("Table name: {0}", metatable.TableName);
        Console.Write("Customer ID: ");
        Console.WriteLine(entityInConflict.CustomerID);
        foreach (MemberChangeConflict mcc in occ.MemberConflicts)
        {
            object currVal = mcc.CurrentValue;
            object origVal = mcc.OriginalValue;
            object databaseVal = mcc.DatabaseValue;
            MemberInfo mi = mcc.Member;
            Console.WriteLine("Member: {0}", mi.Name);
            Console.WriteLine("current value: {0}", currVal);
            Console.WriteLine("original value: {0}", origVal);
            Console.WriteLine("database value: {0}", databaseVal);
        }
    }
}

Pour le faire ignorer le problème et de s'engager de toute façon:

db.SubmitChanges(ConflictMode.ContinueOnConflict);

Autres conseils

Ces (que vous pouvez ajouter dans une classe partielle de votre datacontext peut vous aider à comprendre comment cela fonctionne:

public void SubmitKeepChanges()
{
    try
    {
        this.SubmitChanges(ConflictMode.ContinueOnConflict);
    }
    catch (ChangeConflictException e)
    {
        foreach (ObjectChangeConflict occ in this.ChangeConflicts)
        {
            //Keep current values that have changed, 
//updates other values with database values

            occ.Resolve(RefreshMode.KeepChanges);
        }
    }
}

public void SubmitOverwrite()
{
    try
    {
        this.SubmitChanges(ConflictMode.ContinueOnConflict);
    }
    catch (ChangeConflictException e)
    {
        foreach (ObjectChangeConflict occ in this.ChangeConflicts)
        {
            // All database values overwrite current values with 
//values from database

            occ.Resolve(RefreshMode.OverwriteCurrentValues);
        }
    }
}

public void SubmitKeepCurrent()
{
    try
    {
        this.SubmitChanges(ConflictMode.ContinueOnConflict);
    }
    catch (ChangeConflictException e)
    {
        foreach (ObjectChangeConflict occ in this.ChangeConflicts)
        {
            //Swap the original values with the values retrieved from the database. No current value is modified
            occ.Resolve(RefreshMode.KeepCurrentValues);
        }
    }
}

J'ai obtenu cette erreur dans une circonstance complètement étranger à ce que le message d'erreur décrit.

Ce que j'ai fait a été de charger un objet LINQ via un DataContext, et a ensuite essayé de SubmitChanges() de l'objet par un autre DataContext - a donné exactement le même message d'erreur.

Ce que j'avais à faire était d'appeler DataContext.Table.Attach(myOldObject), puis d'appeler SubmitChanges(), a travaillé comme un charme.

Cela vaut le coup, surtout si vous êtes d'avis qu'il ne devrait pas y avoir de conflits à tous.

L'erreur sur la Ligne "ne trouve pas ou changé" apparaîtront aussi, parfois, quand les colonnes ou les types de l'O/R-Designer qui ne correspondent pas à l'colonnes dans la base de données SQL, surtout si une colonne accepte les valeurs null en SQL mais pas les valeurs null dans l'O/R-Designer.

Afin de vérifier si votre table de mappage dans l'O/R-Designer correspond à votre base de données SQL!

Grâce à @vzczc.J'ai trouvé l'exemple que vous avez donné très utile, mais que je devais appeler SubmitChanges de nouveau après la résolution.Voici mes méthodes modifiées - espérons que cela aide quelqu'un.

    /// <summary>
    /// Submits changes and, if there are any conflicts, the database changes are auto-merged for 
    /// members that client has not modified (client wins, but database changes are preserved if possible)
    /// </summary>
    public void SubmitKeepChanges()
    {
        this.Submit(RefreshMode.KeepChanges);
    }

    /// <summary>
    /// Submits changes and, if there are any conflicts, simply overwrites what is in the database (client wins).
    /// </summary>
    public void SubmitOverwriteDatabase()
    {
        this.Submit(RefreshMode.KeepCurrentValues);
    }

    /// <summary>
    /// Submits changes and, if there are any conflicts, all database values overwrite
    /// current values (client loses).
    /// </summary>
    public void SubmitUseDatabase()
    {
        this.Submit(RefreshMode.OverwriteCurrentValues);
    }

    /// <summary>
    /// Submits the changes using the specified refresh mode.
    /// </summary>
    /// <param name="refreshMode">The refresh mode.</param>
    private void Submit(RefreshMode refreshMode)
    {
        bool moreToSubmit = true;
        do
        {
            try
            {
                this.SubmitChanges(ConflictMode.ContinueOnConflict);
                moreToSubmit = false;
            }
            catch (ChangeConflictException)
            {
                foreach (ObjectChangeConflict occ in this.ChangeConflicts)
                {
                    occ.Resolve(refreshMode);
                }
            }
        }
        while (moreToSubmit);

    }

ligne pas trouvé ou changé, c'est la plupart du temps un problème de la simultanéité

Si un autre utilisateur est en train de changer, le même enregistrement de ces erreurs de popup, car le dossier est déjà modifié par l'utilisateur.Ainsi, lorsque vous voulez éliminer ces erreurs, vous devez gérer la simultanéité dans votre application.Si vous manipulez de la simultanéité bien que vous n'obtenez pas ces erreurs plus.Le code ci-dessus, les échantillons sont un moyen de gérer la simultanéité des erreurs.Ce qui manque, c'est dans le cas d'une simultanéité d'erreur, vous devriez mettre un refresh variable dans ces méthodes, donc quand refresh est true les données doivent être actualisées sur l'écran après la mise à jour de sorte que vous verrez également la mise à jour faite par l'autre utilisateur.

    /// <remarks>
    ///     linq has optimistic concurrency, so objects can be changed by other users, while
    ///     submitted keep database changes but make sure users changes are also submitted
    ///     and refreshed with the changes already made by other users.
    /// </remarks>
    /// <returns>return if a refresh is needed.</returns>
    public bool SubmitKeepChanges()
    {
        // try to submit changes to the database.
        bool refresh = false;
        try
        {
            base.SubmitChanges(ConflictMode.ContinueOnConflict);
        }

        /* 
         * assume a "row not found or changed" exception, if thats the case:
         * - keep the database changes already made by other users and make sure
         * - this users changes are also written to the database
         */
        catch (ChangeConflictException)
        {
            // show where the conflicts are in debug mode
            ShowConflicts();

            // get database values and combine with user changes 
            base.ChangeConflicts.ResolveAll(RefreshMode.KeepChanges);

            // submit those combined changes again to the database.
            base.SubmitChanges();

            // a refresh is needed
            refresh = true;
        }

        // return if a refresh is needed.
        return refresh;
    }

"et aussi, est-il un moyen d'obtenir LINQ d'ignorer le problème et de simplement valider les données, peu importe?"

Vous pouvez définir la Vérification de mise à Jour' de la propriété sur votre entité ne "Jamais" pour arrêter ce champ est utilisé pour l'accès concurrentiel optimiste de la vérification.

Vous pouvez également utiliser:

db.SubmitChanges(ConflictMode.ContinueOnConflict)
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top