2009-11-12 6 views
0

Je LINQ de SubSonic 3 comme ceci:Sub Sonic ne pas fermer les connexions

for(int x; x < 100; x++) { 
    var v = (from c in db.categories 
      where c.parent == 10 
      select c); 

    if (v.Count() > 0) return null; 

    category[] c = v.ToArray(); 
} 

pour une raison quelconque SubSonic ne ferme pas les connexions ... donc après quelques courses de la boucle au-dessus, je RUPTURE des connexions SQL dans le pool ou MySQL refuse simplement d'autoriser plus de connexions ... J'ai essayé ceci à la fois avec SS 3.0.3 et avec SVN, et je continue à recevoir ces erreurs.

Que dois-je faire pour fermer les connexions après avoir obtenu un ensemble de résultats?

Merci

+0

Même si je ne peux pas répondre à votre question, merci de me montrer SubSonic :) Je pense avoir trouvé la solution dont j'ai besoin pour résoudre mes problèmes. – Femaref

Répondre

3

Le problème - croyez-le ou non - ne sont pas subsonique. C'est le pilote MySQL $ * $ & $. Nous fermons explicitement la connexion lorsque vous faites des requêtes comme celle-ci, mais j'ai vu le pilote MySQL ignorer complètement la fermeture au profit de tentatives d'optimisation vraiment, vraiment nulles.

Je ne sais pas quoi vous dire ici - Je suis vraiment désolé de le dire.

+0

Et j'ai encore une autre raison de quitter MySQL .... Merci pour l'aide si. –

3

Il semble y avoir quelques problèmes avec la bibliothèque MySQL .NET. Il y a quelques jours, ils ont corrigé certains de ces problèmes avec 6.2.2 liés à la libération de connexions. Mais il y a aussi un problème avec SubSonic. J'ai utilisé les templates LINQ avec MySQL pour générer mes classes. Chaque fois que FirstOrDefault() ou First() (les autres fonctions similaires ont probablement le même problème).

Pour une requête telle que:

var db = new MyDb("CONNECTIONSTRING_NAME"); 

var userExt = (from pe in db.PhoneExtensions 
       where 
        pe.FirstName.ToLower() == firstName.ToLower() && 
        pe.LastName.ToLower() == lastName.ToLower() 
       select pe.Extension).FirstOrDefault(); 

Cela entraînera la requête à exécuter et le lecteur ne être mis au rebut.

Le problème est dans Linq.Structure.DbQueryProvider dans la méthode Project of T.

while (reader.Read()) 
{ 
    yield return fnProjector(reader); 
} 
reader.Dispose(); 

Le Dispose() ne sera jamais appelé lors de l'utilisation FirstOrDefault() et d'autres méthodes similaires.

Une solution simple:

try 
{ 
    while (reader.Read()) 
    { 
     yield return fnProjector(reader); 
    } 
} 
finally 
{ 
    reader.Dispose(); 
} 

test rapide simple montrant la question:

private class DbDataReader : System.IDisposable 
{ 
    #region IDisposable Members 

    public void Dispose() { } 

    #endregion 
} 
private class DbQueryProvider 
{ 
    private DbDataReader _reader; 

    public bool IsReaderDisposed { get { return _reader == null; } } 

    public DbQueryProvider() 
    { 
     _reader = new DbDataReader(); 
    } 

    public IEnumerable<int> Project(int numResults) 
    { 
     int i = 0; 
     while (i < numResults) 
     { 
      yield return i++; 
     } 
     _reader.Dispose(); 
     _reader = null; 
    } 

    public IEnumerable<int> ProjectWithFinally(int numResults) 
    { 
     int i = 0; 
     try 
     { 
      while (i < numResults) 
      { 
       yield return i++; 
      } 
     } 
     finally 
     { 
      _reader.Dispose(); 
      _reader = null; 
     } 
    } 

} 

[Test] 
public void YieldReturn_Returns_TrueForIsReaderDisposed() 
{ 
    const int numResults = 1; 

    var qp1 = new DbQueryProvider(); 
    var q1 = qp1.Project(numResults); 
    Assert.IsInstanceOf(typeof(int), q1.First()); 

    var qp2 = new DbQueryProvider(); 
    var q2 = qp2.Project(numResults); 
    Assert.IsInstanceOf(typeof(int), q2.FirstOrDefault()); 

    var qp3 = new DbQueryProvider(); 
    var q3 = qp3.Project(numResults); 
    Assert.IsInstanceOf(typeof(int), q3.Single()); 

    var qp4 = new DbQueryProvider(); 
    var q4 = qp4.Project(numResults); 
    Assert.IsInstanceOf(typeof(int), q4.SingleOrDefault()); 

    Assert.IsTrue(qp1.IsReaderDisposed); 
    Assert.IsTrue(qp2.IsReaderDisposed); 
    Assert.IsTrue(qp3.IsReaderDisposed); 
    Assert.IsTrue(qp4.IsReaderDisposed); 
} 

[Test] 
public void YieldReturnFinally_Returns_TrueForIsReaderDisposed() 
{ 
    const int numResults = 1; 

    var qp1 = new DbQueryProvider(); 
    var q1 = qp1.ProjectWithFinally(numResults); 
    Assert.IsInstanceOf(typeof(int), q1.First()); 

    var qp2 = new DbQueryProvider(); 
    var q2 = qp2.ProjectWithFinally(numResults); 
    Assert.IsInstanceOf(typeof(int), q2.FirstOrDefault()); 

    var qp3 = new DbQueryProvider(); 
    var q3 = qp3.ProjectWithFinally(numResults); 
    Assert.IsInstanceOf(typeof(int), q3.Single()); 

    var qp4 = new DbQueryProvider(); 
    var q4 = qp4.ProjectWithFinally(numResults); 
    Assert.IsInstanceOf(typeof(int), q4.SingleOrDefault()); 

    Assert.IsTrue(qp1.IsReaderDisposed); 
    Assert.IsTrue(qp2.IsReaderDisposed); 
    Assert.IsTrue(qp3.IsReaderDisposed); 
    Assert.IsTrue(qp4.IsReaderDisposed); 
} 

YieldReturnFinally_Returns_TrueForIsReaderDisposed passe mais échoue YieldReturn_Returns_TrueForIsReaderDisposed.

J'ai testé cela sur le projet sur lequel je travaille qui sera bientôt en production et cela semble fonctionner sans aucun problème. Testé avec une taille maximale de pool de connexion de 5 et n'a pas eu de problèmes de pool de connexion (jamais manqué de connexions sur ma machine de développement lorsque je fais une requête à la fois). J'ai également trouvé des problèmes dans Extensions.Database liés au changement de type et aux affectations.

J'ai forké le projet sur github, j'ai engagé mes modifications et j'ai fait une requête de tirage, avec un peu de chance, je suis arrivé aux bonnes personnes.

Questions connexes