2013-04-30 2 views
0

Je reçois l'erreur suivante dans l'un de nos environnements. Il semble se produire lorsque IIS est redémarré, mais nous n'avons pas réduit les détails pour le reproduire.Obtention d'une erreur lors de la création d'un objet Query dans SubSonic

A DataTable named 'PeoplePassword' already belongs to this DataSet. 
at System.Data.DataTableCollection.RegisterName(String name, String tbNamespace) 
at System.Data.DataTableCollection.BaseAdd(DataTable table) 
at System.Data.DataTableCollection.Add(DataTable table) 
at SubSonic.SqlDataProvider.GetTableSchema(String tableName, TableType tableType) 
at SubSonic.DataService.GetSchema(String tableName, String providerName, TableType tableType) 
at SubSonic.DataService.GetTableSchema(String tableName, String providerName) 
at SubSonic.Query..ctor(String tableName) 
at Wad.Elbert.Data.Enrollment.FetchByUserId(Int32 userId) 

Basé sur le stacktrace, je crois que l'erreur se produit sur la deuxième ligne de la méthode tout en créant l'objet de la requête. S'il vous plaît laissez-moi savoir si quelqu'un d'autre a ce problème. Merci!

Le code de la fonction est:

 public static List<Enrollment> FetchByUserId(int userId) 
    { 
     List<Enrollment> enrollments = new List<Enrollment>(); 
     SubSonic.Query query = new SubSonic.Query("Enrollment"); 
     query.SelectList = "userid, prompt, response, validationRegex, validationMessage, responseType, enrollmentSource"; 
     query.QueryType = SubSonic.QueryType.Select; 
     query.AddWhere("userId", userId); 
     DataSet dataset = query.ExecuteDataSet(); 
     if (dataset != null && 
      dataset.Tables.Count > 0) 
     { 
      foreach (DataRow dr in dataset.Tables[0].Rows) 
      { 
       enrollments.Add(new Enrollment((int)dr["userId"], dr["prompt"].ToString(), dr["response"].ToString(), dr["validationRegex"] != null ? dr["validationRegex"].ToString() : string.Empty, dr["validationMessage"] != null ? dr["validationMessage"].ToString() : string.Empty, (int)dr["responseType"], (int)dr["enrollmentSource"])); 
      } 
     } 
     return enrollments; 
    } 
+0

Pas une réponse, mais utilisez-vous la dernière version 2.x de github? –

Répondre

0

Ceci est un problème de filetage.

Charges subsoniques c'est le schéma sur le premier appel de SubSonic.DataService.GetTableSchema(...) mais ce n'est pas thread sécurisé.

Permettez-moi démontrerai cela avec un petit exemple

private static Dictionary<string, DriveInfo> drives = new Dictionary<string, DriveInfo>; 

private static DriveInfo GetDrive(string name) 
{ 
    if (drives.Count == 0) 
    { 
     Thread.Sleep(10000); // fake delay 
     foreach(var drive in DriveInfo.GetDrives) 
      drives.Add(drive.Name, drive); 
    } 
    if (drives.ContainsKey(name)) 
     return drives[name]; 
    return null; 
} 

ce qui explique bien ce qui se passe, le premier appel à cette méthode, le dictionnaire est vide
Si tel est le cas, la méthode précharger tous les lecteurs.

Pour chaque appel, le lecteur demandé (ou null) est renvoyé.

Mais que se passe-t-il si vous déclenchez la méthode deux fois directement après le démarrage? Ensuite, les deux exécutions tentent de charger les lecteurs dans le dictionnaire. Le premier à ajouter un lecteur gagne le second lancera une ArgumentException (l'élément existe déjà). Après la précharge initiale, tout fonctionne correctement.

En bref, vous avez deux choix.

  1. Modifiez la source subsonique pour rendre SubSonic.DataService.GetTableSchema(...) sans danger pour les threads. "Warmup" subsonic avant d'accepter les demandes. La technique pour réaliser cela dépend de la conception de votre application. Pour ASP.NET, vous avez une méthode Application_Start qui est exécutée une seule fois au cours de votre cycle de vie de l'application http://msdn.microsoft.com/en-us/library/ms178473(v=vs.100).aspx

vous pouvez donc essentiellement mettre un

var count = new SubSonic.Query("Enrollment").GetRecordCount(); 

dans la méthode pour forcer subsonique à initialiser la table schéma lui-même.

Questions connexes