Question

I've been using Subsonic 3.0.0.4 (ActiveRecord approach) for a while, and I recently coded a small page that basically retrieves about 500 records for a given year, and then i just loop through each of them, creating new instances of the Active Record class, just modifying the Period field, and saving each instance in the loop.

The issue is that after executing that page, a LOT of SQL connections are left hanging/open in SQL server (by looking at the sp_who2). Before the page finishes executing, I get the "Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool. This may have occurred because all pooled connections were in use and max pool size was reached." error.

The code is the following:

if (string.IsNullOrEmpty(tbPeriodoAGenerar.Text)) return;

    var idPeriodo = Convert.ToInt32(tbPeriodoAGenerar.Text);



    var nuevaEncuesta = new Encuesta();

    nuevaEncuesta.IdPeriodo = idPeriodo;
    nuevaEncuesta.IdResponsable = 1;
    nuevaEncuesta.fechaCierre1 = Convert.ToDateTime(dpFechaCierre1.Value);
    nuevaEncuesta.fechaCierre2 = Convert.ToDateTime(dpFechaCierre2.Value);
    nuevaEncuesta.IdTipoEncuesta = (int)ETipoEncuesta.PorAnio;
    nuevaEncuesta.nombreEncuesta = NombresEncuestas.COVA;
    nuevaEncuesta.nombrePublico = NombresEncuestas.COVA_PUBLICO;

    nuevaEncuesta.Save();


    var empresasActivas = Empresa.Find(x => x.activo == 1);

    foreach (var empresa in empresasActivas)
    {
        EmpresaEncuesta ee = new EmpresaEncuesta();

        ee.IdEmpresa = empresa.IdEmpresa;
        ee.IdEncuesta = nuevaEncuesta.IdEncuesta;
        ee.IdEstatusContestado = (int)EEstatusEmpresaEncuesta.SinContestar;
        ee.fechaMod = DateTime.Now;
        ee.IdUsuario = 1;
        ee.ipMod = IpUsuarioActual;
        ee.Save();
    }


    if (chkMigrarRespuestas.Checked)
    {


        var periodosAnteriores = new EncuestaBO().ObtenerPeriodosAnteriores(NombresEncuestas.COVA, idPeriodo);
        int? periodoAnterior = null;

        if (periodosAnteriores.Tables[0].Rows.Count > 0)
        {
            periodoAnterior = Convert.ToInt32(periodosAnteriores.Tables[0].Rows[0][Columnas.ID_PERIODO]);
        }

        if (!periodoAnterior.HasValue) return;


        var respuestasCortoPlazo = COVACortoPlazo.Find(x => x.Periodo == (periodoAnterior));
        COVACortoPlazo ccp;

        foreach (var ccpAnterior in respuestasCortoPlazo)
        {
            if (!empresasActivas.Where(emp => emp.IdEmpresa == ccpAnterior.IdEmpresa).Any()) continue;

            ccp = new COVACortoPlazo();

            ccp.IdEmpresa = ccpAnterior.IdEmpresa;
            ccp.CuentaCortoPlazo = ccpAnterior.CuentaCortoPlazo;
            ccp.ComentariosAdicionales = ccpAnterior.ComentariosAdicionales;
            ccp.RetiroVoluntarioOpcionId = ccpAnterior.RetiroVoluntarioOpcionId;
            ccp.RetiroVoluntarioOtroDesc = ccpAnterior.RetiroVoluntarioOtroDesc;
            ccp.RetiroEmpresaOpcionId = ccpAnterior.RetiroEmpresaOpcionId;
            ccp.RetiroEmpresaOtroDesc = ccpAnterior.RetiroEmpresaOtroDesc;

            ccp.Periodo = idPeriodo;

            ccp.Save();
        }



        var tablaCortoPlazoAnterior = COVATablaCortoPlazo.Find(x => x.Periodo == (periodoAnterior));
        COVATablaCortoPlazo ctcp;

        foreach (var ctcpAnterior in tablaCortoPlazoAnterior)
        {
            if (!empresasActivas.Where(emp => emp.IdEmpresa == ctcpAnterior.IdEmpresa).Any()) continue;

            ctcp = new COVATablaCortoPlazo();

            ctcp.IdEmpresa = ctcpAnterior.IdEmpresa;
            ctcp.Periodo = idPeriodo;

            ctcp.COVASegmentoOpcionId = ctcpAnterior.COVASegmentoOpcionId;
            ctcp.NivelDinamicaMin = ctcpAnterior.NivelDinamicaMin;
            ctcp.NivelDinamicaMax = ctcpAnterior.NivelDinamicaMax;

            ctcp.NombreBono = ctcpAnterior.NombreBono;
            ctcp.COVAPeriodicidadOpcionId = ctcpAnterior.COVAPeriodicidadOpcionId;
            ctcp.MetodoCalculo = ctcpAnterior.MetodoCalculo;
            ctcp.COVABaseCalculoOpcionId = ctcpAnterior.COVABaseCalculoOpcionId;
            ctcp.RealAnualizado = ctcpAnterior.RealAnualizado;

            ctcp.Save();
        }



        var respuestasAnual = COVAAnual.Find(x => x.Periodo == (periodoAnterior));
        COVAAnual ca;

        foreach (var caAnterior in respuestasAnual)
        {
            if (!empresasActivas.Where(emp => emp.IdEmpresa == caAnterior.IdEmpresa).Any()) continue;

            ca = new COVAAnual();

            ca.IdEmpresa = caAnterior.IdEmpresa;
            ca.CuentaAnual = caAnterior.CuentaAnual;
            ca.NombreBono = caAnterior.NombreBono;
            ca.FechaPago = caAnterior.FechaPago;

            ca.ComentariosAdicionales = caAnterior.ComentariosAdicionales;

            ca.RetiroVoluntarioOpcionId = caAnterior.RetiroVoluntarioOpcionId;
            ca.RetiroVoluntarioOtroDesc = caAnterior.RetiroVoluntarioOtroDesc;
            ca.RetiroEmpresaOpcionId = caAnterior.RetiroEmpresaOpcionId;
            ca.RetiroEmpresaOtroDesc = caAnterior.RetiroEmpresaOtroDesc;

            ca.Periodo = idPeriodo;

            ca.Save();
        }



        var tablaAnualAnterior = COVATablaAnual.Find(x => x.Periodo == (periodoAnterior));
        COVATablaAnual cta;

        foreach (var ctaAnterior in tablaAnualAnterior)
        {
            if (!empresasActivas.Where(emp => emp.IdEmpresa == ctaAnterior.IdEmpresa).Any()) continue;

            cta = new COVATablaAnual();

            cta.IdEmpresa = ctaAnterior.IdEmpresa;
            cta.Periodo = idPeriodo;

            cta.COVASegmentoOpcionId = ctaAnterior.COVASegmentoOpcionId;
            cta.NivelDinamicaMin = ctaAnterior.NivelDinamicaMin;
            cta.NivelDinamicaMax = ctaAnterior.NivelDinamicaMax;

            cta.Minimo = ctaAnterior.Minimo;
            cta.Target = ctaAnterior.Target;
            cta.Maximo = ctaAnterior.Maximo;

            cta.RealAnualPagado = ctaAnterior.RealAnualPagado;
            cta.MetodoCalculo = ctaAnterior.MetodoCalculo;
            cta.COVABaseCalculoOpcionId = ctaAnterior.COVABaseCalculoOpcionId;

            cta.Save();
        }



        var respuestasLargoPlazo = COVALargoPlazo.Find(x => x.Periodo == (periodoAnterior));
        COVALargoPlazo clp;

        foreach (var clpAnterior in respuestasLargoPlazo)
        {
            if (!empresasActivas.Where(emp => emp.IdEmpresa == clpAnterior.IdEmpresa).Any()) continue;

            clp = new COVALargoPlazo();

            clp.IdEmpresa = clpAnterior.IdEmpresa;
            clp.CuentaLargoPlazo = clpAnterior.CuentaLargoPlazo;
            clp.ComentariosAdicionales = clpAnterior.ComentariosAdicionales;

            clp.RetiroVoluntarioOpcionId = clpAnterior.RetiroVoluntarioOpcionId;
            clp.RetiroVoluntarioOtroDesc = clpAnterior.RetiroVoluntarioOtroDesc;
            clp.RetiroEmpresaOpcionId = clpAnterior.RetiroEmpresaOpcionId;
            clp.RetiroEmpresaOtroDesc = clpAnterior.RetiroEmpresaOtroDesc;

            clp.PermiteCompraAcciones = clpAnterior.PermiteCompraAcciones;

            clp.Periodo = idPeriodo;

            clp.Save();
        }



        var tablaLargoPlazoAnterior = COVATablaLargoPlazo.Find(x => x.Periodo == (periodoAnterior));
        COVATablaLargoPlazo ctlp;

        foreach (var ctlpAnterior in tablaLargoPlazoAnterior)
        {
            if (!empresasActivas.Where(emp => emp.IdEmpresa == ctlpAnterior.IdEmpresa).Any()) continue;

            ctlp = new COVATablaLargoPlazo();

            ctlp.IdEmpresa = ctlpAnterior.IdEmpresa;
            ctlp.Periodo = idPeriodo;

            ctlp.NombrePlan = ctlpAnterior.NombrePlan;
            ctlp.COVATipoPlanOpcionId = ctlpAnterior.COVATipoPlanOpcionId;


            ctlp.COVASegmentoOpcionId = ctlpAnterior.COVASegmentoOpcionId;
            ctlp.NivelDinamicaMin = ctlpAnterior.NivelDinamicaMin;
            ctlp.NivelDinamicaMax = ctlpAnterior.NivelDinamicaMax;


            ctlp.RealPagadoFinalPlan = ctlpAnterior.RealPagadoFinalPlan;
            ctlp.AniosEjerce = ctlpAnterior.AniosEjerce;
            ctlp.MetodoCalculo = ctlpAnterior.MetodoCalculo;
            ctlp.BaseCalculo = ctlpAnterior.BaseCalculo;

            ctlp.Save();
        }


        var respuestasVentas = COVAVentas.Find(x => x.Periodo == (periodoAnterior));
        COVAVentas cv;

        foreach (var cvAnterior in respuestasVentas)
        {
            if (!empresasActivas.Where(emp => emp.IdEmpresa == cvAnterior.IdEmpresa).Any()) continue;

            cv = new COVAVentas();

            cv.IdEmpresa = cvAnterior.IdEmpresa;
            cv.CuentaVentas = cvAnterior.CuentaVentas;
            cv.ComentariosAdicionales = cvAnterior.ComentariosAdicionales;

            cv.RetiroVoluntarioOpcionId = cvAnterior.RetiroVoluntarioOpcionId;
            cv.RetiroVoluntarioOtroDesc = cvAnterior.RetiroVoluntarioOtroDesc;
            cv.RetiroEmpresaOpcionId = cvAnterior.RetiroEmpresaOpcionId;
            cv.RetiroEmpresaOtroDesc = cvAnterior.RetiroEmpresaOtroDesc;

            cv.Periodo = idPeriodo;

            cv.Save();
        }




        var tablaVentasAnterior = COVATablaVentas.Find(x => x.Periodo == (periodoAnterior));
        COVATablaVentas ctv;

        foreach (var ctvAnterior in tablaVentasAnterior)
        {
            if (!empresasActivas.Where(emp => emp.IdEmpresa == ctvAnterior.IdEmpresa).Any()) continue;

            ctv = new COVATablaVentas();

            ctv.IdEmpresa = ctvAnterior.IdEmpresa;
            ctv.Periodo = idPeriodo;

            ctv.COVASegmentoOpcionId = ctvAnterior.COVASegmentoOpcionId;
            ctv.COVAPeriodicidadOpcionId = ctvAnterior.COVAPeriodicidadOpcionId;

            ctv.Minimo = ctvAnterior.Minimo;
            ctv.Target = ctvAnterior.Target;
            ctv.Maximo = ctvAnterior.Maximo;

            ctv.RealAnualizado = ctvAnterior.RealAnualizado;
            ctv.MetodoCalculo = ctvAnterior.MetodoCalculo;
            ctv.BaseCalculo = ctvAnterior.BaseCalculo;

            ctv.Save();
        }




        var respuestasGenerales = COVAGenerales.Find(x => x.Periodo == (periodoAnterior));
        COVAGenerales cg;

        foreach (var cgAnterior in respuestasGenerales)
        {
            if (!empresasActivas.Where(emp => emp.IdEmpresa == cgAnterior.IdEmpresa).Any()) continue;

            cg = new COVAGenerales();

            cg.IdEmpresa = cgAnterior.IdEmpresa;

            cg.AccionesPorSituacionActual = cgAnterior.AccionesPorSituacionActual;
            cg.ComentariosAccionesSituacionActual = cgAnterior.ComentariosAccionesSituacionActual;
            cg.TomaCuentaSituacionDefinicionObjetivos = cgAnterior.TomaCuentaSituacionDefinicionObjetivos;


            cg.Periodo = idPeriodo;

            cg.Save();
        }
    }

Am I doing it the wrong way? At this point, I am not sure if this is a Subsonic bug or if I need to manually close the connection myself somehow.

I've googled for posts about similar problems when using subsonic, but none have come up. The usual cause for the error I get is not closing the SqlDataReader, but I honestly do not believe Subsonic is not closing it..and Im using the latest version.

Any ideas? Any help is greatly appreciated.

Was it helpful?

Solution

Any time you have a loop on an ORM-based object you have to consider there's probably an N+1 issue. I can't see your model, but I'll bet that in your loop you're executing a number of additional queries.

I know that Save() fires and closes an ExecuteScalar() - this should not leave a connection open. However, if you're fetching related records inside that loop - yeah that could have problems.

So - I would recommend using a profiler of some kind and the debugger to step through your loop - see what queries are made.

Alternatively - this is ripe for using the BatchInsert stuff which would keep everything in a nice, tidy single-connection transaction.

Read here for more: http://subsonic.wekeroad.com/docs/Linq_Inserts

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top