web-dev-qa-db-fra.com

La nouvelle transaction Entity Framework n'est pas autorisée car d'autres threads sont en cours d'exécution dans la session, enregistrement multi-thread

J'essaie de sauvegarder sur une base de données le journal d'un processus multi-thread, mais le message d'erreur suivant s'affiche: la nouvelle transaction n'est pas autorisée car d'autres threads s'exécutent dans la session.

dans chaque marche j'ai cette fonction:

 internal bool WriteTrace(IResult result, string message, byte type)
    {
        SPC_SENDING_TRACE trace = new SPC_SENDING_TRACE(
                        message,
                        Parent.currentLine.CD_LINE,
                        type,
                        Parent.currentUser.FULLNAME,
                        Parent.guid);
        Context.SPC_SENDING_TRACE.AddObject(trace);
        if (Context.SaveChanges(result) == false)
            return false;
        return true;

    }

le contexte est différent pour chaque thread, mais la connexion avec la base de données est toujours la même.

y a-t-il un moyen de résoudre ce problème?

merci Andrea

9
andrea

Vous devriez créer un contexte pour chaque transaction et ensuite le disposer, vous pouvez le faire comme ceci:

using(var ctx = new MyContext()) {
    //do transaction here
}

Après le crochet fermé, le contexte est éliminé.

Pour une meilleure compréhension, reportez-vous à cet article où vous pouvez trouver une bonne réponse de ken2k . J'espère que vous pourrez résoudre votre problème :)

UPDATE:

Vous devez également essayer d'ajouter .ToList() à chaque requête LINQ que vous avez. Lorsque vous parcourez un résultat LINQ, vous ne pouvez apporter aucune modification avant la fin de l'itération. Vérifiez si vous avez quelque chose comme ça ou partagez plus de code, c'est-à-dire le morceau de code où vous appelez WriteTrace. Espérons que cette fois, cela vous aide réellement.

35
ecampver

J'utilise la structure d'entités dans un environnement multithread, dans lequel n'importe quel thread, interface utilisateur et arrière-plan (STA et MTA) peuvent simultanément mettre à jour la même base de données. J'ai résolu ce problème en recréant la connexion d'entité à partir de zéro au début de l'utilisation sur tout nouveau thread en arrière-plan. Examen de l'instance de connexion d'entité ConnectionString montre un guide de lecteur qui, je suppose, est utilisé pour lier des instances de connexion courantes. En recréant la connexion d'entité à partir de zéro, les valeurs guid sont différentes pour chaque thread et aucun conflit ne semble se produire.

// Build the connection string.

  var sqlBuilder = new SqlConnectionStringBuilder();
  sqlBuilder.DataSource = serverName;
  sqlBuilder.InitialCatalog = databaseName;
  sqlBuilder.MultipleActiveResultSets = true;
  ...
  var providerString = sqlBuilder.ToString();
  var sqlConnection = new SqlConnection(providerString);

// Build the emtity connection.

  Assembly metadataAssembly = Assembly.GetExecutingAssembly();
  Assembly[] metadataAssemblies = { metadataAssembly };
  var metadataBase = @"res://*/{0}.csdl|res://*/{0}.ssdl|res://*/{0}.msl";
  var dbModelMetadata = String.Format(metadataBase, objectContextTypeModelName);
  // eg: "res://*/Models.MyDatabaseModel.csdl|res://*/Models.MyDatabaseModel.ssdl|res://*/Models.MyDatabaseModel.msl"
  var modelMetadataPaths = modelMetadata.Split('|');
  var metadataWorkspace = new MetadataWorkspace(modelMetadataPaths, metadataAssemblies);
  var entityDbConnection = new EntityConnection(metadataWorkspace, sqlConnection);
  return entityDbConnection;
0
David Coleman