如何使用相同的SQL Server 2012连接管理多个Winform实例?

时间:2014-05-13 18:25:25

标签: c# sql .net sql-server winforms

我有一个Winforms C#应用程序,它对SQL Server 2012数据库进行了大量查询。此数据库没有外键,在winforms应用程序中,我有一个数据层,使用System.Data.Common.DbConnection对象管理与数据库的连接

这个Winform应用程序打开时,它在主窗体上有一个Timer,它保持连接打开如下:

private void timerConexion_Tick(object sender, EventArgs e)
        {
            bool todoOK = false;
            if (this.Datos != null)
                if (this.Datos.Conexion != null)
                    if (this.Datos.Conexion.State == ConnectionState.Open)
                    {
                        todoOK = true;
                    }
            if (!todoOK)
            {
                this.timerConexion.Enabled = false;
                // The application must be close
                MessageBox.Show("¡Connection with the server is lost!\r\nThe application will be closed.", ConfigurationManager.AppSettings["TitleMessageBox"], MessageBoxButtons.OK, MessageBoxIcon.Stop);
                Application.Exit();
            }
        }

我的问题是,我有20-30台PC运行这个Winform应用程序,并且有几次我有事务锁,我必须杀死进程以释放这些锁。 我想创建一个更好的DB连接,但我不知道什么是最好的选择...如果我使用实体框架它会很痛苦...因为我的数据库上没有任何FK。

我最好的选择是什么?

这是我的数据层:

[CLSCompliant(true)]
    public class Datos
    {

        private DbConnection conexion = null;

        public DbConnection Conexion
        {
            get { return conexion; }
        }

        private DbCommand comando = null;

        public DbCommand Comando
        {
            get { return comando; }
        }
        private DbTransaction transaccion = null;

        public DbTransaction Transaccion
        {
            get { return transaccion; }
        }
        private string cadenaConexion;

        public string CadenaConexion
        {
            get { return cadenaConexion; }
            set { cadenaConexion = value; }
        }

        private static DbProviderFactory factory = null;

        private ProveedorDatos proveedor;

        /// <summary>
        /// Crea una instancia del acceso a la base de datos.
        /// </summary>
        public Datos(ProveedorDatos proveedor)
        {
            this.proveedor = proveedor;
            Configurar();
        }

        /// <summary>
        /// Configura el acceso a la base de datos para su utilización.
        /// </summary>
        /// <exception cref="DatosException">Si existe un error al cargar la configuración.</exception>
        private void Configurar()
        {
            try
            {
                string proveedor = "";
                switch (this.proveedor)
                {
                    case ProveedorDatos.SqlServer:
                        proveedor = ConfigurationManager.AppSettings.Get("PROVEEDOR_ADONET");
                        this.cadenaConexion = ConfigurationManager.AppSettings.Get("CADENA_CONEXION");
                        break;
                    case ProveedorDatos.FoxDbf:
                        proveedor = ConfigurationManager.AppSettings.Get("PROVEEDOR_OLEDB");
                        this.cadenaConexion = ConfigurationManager.AppSettings.Get("CADENA_CONEXION_DBF");
                        break;
                }
                Datos.factory = DbProviderFactories.GetFactory(proveedor);
            }
            catch (ConfigurationException ex)
            {
                throw new DatosException("Error al cargar la configuración del acceso a datos.", ex);
            }
        }

        /// <summary>
        /// Permite desconectarse de la base de datos.
        /// </summary>
        public void Desconectar()
        {
            if (this.conexion.State.Equals(ConnectionState.Open))
            {
                this.conexion.Close();
            }
        }

        /// <summary>
        /// Se concecta con la base de datos.
        /// </summary>
        /// <exception cref="DatosException">Si existe un error al conectarse.</exception>
        public void Conectar()
        {
            if (this.conexion != null && !this.conexion.State.Equals(ConnectionState.Closed))
            {
                throw new DatosException("La conexión ya se encuentra abierta.");
            }
            try
            {
                if (this.conexion == null)
                {
                    this.conexion = factory.CreateConnection();
                    this.conexion.ConnectionString = cadenaConexion;
                }
                this.conexion.Open();
            }
            catch (SqlException ex)
            {
                throw new DatosException("Hubo un error en la instancia de SQL Server.", ex);
            }
            catch (DataException ex)
            {
                throw new DatosException("Error al conectarse a la base de datos.", ex);
            }
        }

        /// <summary>
        /// Aplica los roles de seguridad para el acceso a la base de datos
        /// </summary>
        public bool AplicarRoles(string roleApp, string roleAppPwd)
        {
            try
            {
                System.Data.SqlClient.SqlCommand commandoRoles = new System.Data.SqlClient.SqlCommand("EXEC sp_setapprole '" + roleApp + "', '" + roleAppPwd + "'", (System.Data.SqlClient.SqlConnection)conexion);
                int resultado = commandoRoles.ExecuteNonQuery();
                commandoRoles.Dispose();
                commandoRoles = null;
                if (resultado == -1)
                    return true;
                else
                    return false;
            }
            catch
            {
                return false;
            }
        }

        /// <summary>
        /// Crea un comando en base a una sentencia SQL.
        /// Ejemplo:
        /// <code>SELECT * FROM Tabla WHERE campo1=@campo1, campo2=@campo2</code>
        /// Guarda el comando para el seteo de parámetros y la posterior ejecución.
        /// </summary>
        /// <param name="sentenciaSQL">La sentencia SQL con el formato: SENTENCIA [param = @param,]</param>
        public void CrearComando(string sentenciaSQL)
        {
            if (this.comando != null)
            {
                this.comando.Dispose();
                this.comando = null;
            }
            this.comando = factory.CreateCommand();
            this.comando.Connection = this.conexion;
            this.comando.CommandType = CommandType.Text;
            this.comando.CommandText = sentenciaSQL;
            if (this.transaccion != null)
            {
                this.comando.Transaction = this.transaccion;
            }
        }

        public void CrearComandoStoredProcedure(string procedureName)
        {
            if (comando != null)
            {
                comando.Dispose();
                comando = null;
            }
            comando = factory.CreateCommand();
            comando.Connection = conexion;
            comando.CommandType = CommandType.StoredProcedure;
            comando.CommandText = procedureName;
        }

        public void AsignarParametro(string nombre, object valor, SqlDbType tipo)
        {
            var parameter = new SqlParameter(nombre, tipo)
            {
                Value = valor ?? DBNull.Value
            };
            comando.Parameters.Add(parameter);
        }

        /// <summary>
        /// Setea un parámetro como nulo del comando creado.
        /// </summary>
        /// <param name="nombre">El nombre del parámetro cuyo valor será nulo.</param>
        public void AsignarParametroNulo(string nombre)
        {
            AsignarParametro(nombre, "", "NULL");
        }

        /// <summary>
        /// Asigna un parámetro de tipo cadena al comando creado.
        /// </summary>
        /// <param name="nombre">El nombre del parámetro.</param>
        /// <param name="valor">El valor del parámetro.</param>
        public void AsignarParametroCadena(string nombre, string valor)
        {
            AsignarParametro(nombre, "'", valor.ToString());
        }

        /// <summary>
        /// Asigna un parámetro de tipo entero al comando creado.
        /// </summary>
        /// <param name="nombre">El nombre del parámetro.</param>
        /// <param name="valor">El valor del parámetro.</param>
        public void AsignarParametroEntero(string nombre, int valor)
        {
            AsignarParametro(nombre, "", valor.ToString());
        }

        /// <summary>
        /// Asigna un parámetro de tipo entero al comando creado.
        /// </summary>
        /// <param name="nombre">El nombre del parámetro.</param>
        /// <param name="valor">El valor del parámetro.</param>
        public void AsignarParametroEntero(string nombre, long valor)
        {
            AsignarParametro(nombre, "", valor.ToString());
        }

        /// <summary>
        /// Asigna un parámetro de tipo numerico al comando creado.
        /// </summary>
        /// <param name="nombre">El nombre del parámetro.</param>
        /// <param name="valor">El valor del parámetro.</param>
        public void AsignarParametroNumerico(string nombre, double valor)
        {
            AsignarParametro(nombre, "", valor.ToString().Replace(',', '.'));
        }

        /// <summary>
        /// Asigna un parámetro de tipo bit al comando creado.
        /// </summary>
        /// <param name="nombre">El nombre del parámetro.</param>
        /// <param name="valor">El valor del parámetro.</param>
        public void AsignarParametroBit(string nombre, bool valor)
        {
            if (valor)
                AsignarParametro(nombre, "", "1");
            else
                AsignarParametro(nombre, "", "0");
        }

        ///// <summary>
        ///// Asigna un parámetro de tipo numeric al comando creado.
        ///// </summary>
        ///// <param name="nombre">El nombre del parámetro.</param>
        ///// <param name="valor">El valor del parámetro.</param>
        //public void AsignarParametroNumerico(string nombre, double valor)
        //{
        //    AsignarParametro(nombre, "", valor.ToString());
        //}

        /// <summary>
        /// Asigna un parámetro al comando creado.
        /// </summary>
        /// <param name="nombre">El nombre del parámetro.</param>
        /// <param name="separador">El separador que será agregado al valor del parámetro.</param>
        /// <param name="valor">El valor del parámetro.</param>
        private void AsignarParametro(string nombre, string separador, string valor)
        {
            int indice = this.comando.CommandText.IndexOf(nombre);
            string prefijo = this.comando.CommandText.Substring(0, indice);
            string sufijo = this.comando.CommandText.Substring(indice + nombre.Length);
            this.comando.CommandText = prefijo + separador + valor + separador + sufijo;
        }

        /// <summary>
        /// Asigna un parámetro de tipo fecha al comando.
        /// </summary>
        /// <param name="nombre">El nombre del parámetro.</param>
        /// <param name="valor">El valor del parámetro.</param>
        public void AsignarParametroFecha(string nombre, DateTime valor)
        {
            var parameter = new SqlParameter(nombre, SqlDbType.DateTime)
            {
                Value = valor
            };
            comando.Parameters.Add(parameter);
            //AsignarParametro(nombre, "'", valor.ToString("yyyyMMdd HH:mm:ss"));
        }

        /// <summary>
        /// Asigna un parámetro de tipo fecha al comando.
        /// </summary>
        /// <param name="nombre">El nombre del parámetro.</param>
        /// <param name="valor">El valor del parámetro.</param>
        public void AsignarParametroFechaCorta(string nombre, DateTime valor)
        {
            var parameter = new SqlParameter(nombre, SqlDbType.DateTime)
            {
                Value = valor
            };
            comando.Parameters.Add(parameter);
            //AsignarParametro(nombre, "'", valor.ToString("yyyyMMdd"));
        }

        /// <summary>
        /// Ejecuta el comando creado y retorna el resultado de la consulta.
        /// </summary>
        /// <returns>El resultado de la consulta.</returns>
        /// <exception cref="DatosException">Si ocurre un error al ejecutar el comando.</exception>
        public DbDataReader EjecutarConsulta()
        {
            this.comando.CommandTimeout = 120;
            return this.comando.ExecuteReader();
        }

        /// <summary>
        /// Ejecuta el comando creado y retorna el resultado de la consulta en un DbDataAdapter.
        /// </summary>
        /// <returns>El resultado de la consulta.</returns>
        /// <exception cref="DatosException">Si ocurre un error al ejecutar el comando.</exception>
        public DbDataAdapter EjecutarConsultaDS()
        {
            DbDataAdapter adaptador = factory.CreateDataAdapter();
            adaptador.SelectCommand = comando;
            return adaptador;
        }

        /// <summary>
        /// Ejecuta el comando creado y retorna un escalar.
        /// </summary>
        /// <returns>El escalar que es el resultado del comando.</returns>
        /// <exception cref="DatosException">Si ocurre un error al ejecutar el comando.</exception>
        public int EjecutarEscalar()
        {
            int escalar = 0;
            try
            {
                object exit = this.comando.ExecuteScalar();
                if (exit != null)
                {
                    int.TryParse(exit.ToString(), out escalar);
                }
            }
            catch (InvalidCastException ex)
            {
                throw new DatosException("Error al ejecutar un escalar.", ex);
            }
            return escalar;

        }


        public T EjecutarEscalar<T>()
        {
            try
            {
                object exit = this.comando.ExecuteScalar();
                Type t = typeof(T);
                t = Nullable.GetUnderlyingType(t) ?? t;

                return (exit == null || DBNull.Value.Equals(exit)) ?
                   default(T) : (T)Convert.ChangeType(exit, t);
            }
            catch (InvalidCastException ex)
            {
                throw new DatosException("Error al ejecutar un escalar.", ex);
            }
        }

        public T EjecutarValorStoredProcedure<T>(string returnName, SqlDbType returnType)
        {
            var parameter = new SqlParameter(returnName, returnType)
            {
                Direction = ParameterDirection.ReturnValue
            };
            comando.Parameters.Add(parameter);
            comando.ExecuteNonQuery();
            object value = comando.Parameters[returnName].Value;
            return (T) value;
        }

        /// <summary>
        /// Ejecuta el comando creado.
        /// </summary>
        public void EjecutarComando()
        {
            this.comando.ExecuteNonQuery();
        }

        /// <summary>
        /// Ejecuta el comando creado.
        /// </summary>
        public int EjecutarComandoInt()
        {
            return this.comando.ExecuteNonQuery();
        }


        /// <summary>
        /// Comienza una transacción en base a la conexion abierta.
        /// Todo lo que se ejecute luego de esta ionvocación estará 
        /// dentro de una tranasacción.
        /// </summary>
        public void ComenzarTransaccion()
        {
            if (this.transaccion == null)
            {
                this.transaccion = this.conexion.BeginTransaction(IsolationLevel.Serializable);
            }
        }

        /// <summary>
        /// Cancela la ejecución de una transacción.
        /// Todo lo ejecutado entre ésta invocación y su 
        /// correspondiente <c>ComenzarTransaccion</c> será perdido.
        /// </summary>
        public void CancelarTransaccion()
        {
            if (this.transaccion != null)
            {
                this.transaccion.Rollback();
            }
            this.transaccion.Dispose();
            this.transaccion = null;
        }

        /// <summary>
        /// Confirma todo los comandos ejecutados entre el <c>ComanzarTransaccion</c>
        /// y ésta invocación.
        /// </summary>
        public void ConfirmarTransaccion()
        {
            if (this.transaccion != null)
            {
                this.transaccion.Commit();
            }
            this.transaccion.Dispose();
            this.transaccion = null;
        }

    }

修改:我忘了说主要表单的Main Program.cs方法创建了连接,如下所示:

Datos datos = new Datos(ProveedorDatos.SqlServer);
datos.Conectar();
Application.Run(new FrmApp(datos));
datos.Desconectar();

1 个答案:

答案 0 :(得分:0)

我认为问题是每次函数调用factory.CreateConnection()时都要创建一个新连接,这样就可以创建多个连接。我没看到你是在处理它(connection.Dispose())。

尝试两件事:

  • 使用&#34;使用&#34;创建新连接时的关键字,因此您不必担心处置它。

  • 为de conection实现单例或多重:

    Singleton就是这样的:

    public class Singleton {
      private static Singleton theInstance;
      private Singleton(){
        theInstance=null;
      }
      public static Singleton getInstance(){
       if ( theInstance==null )
         theInstance= new Singleton();
         return theInstance;
       }
    }
    

    您有一个连接类的实例,当该实例为null时,您创建一个新实例,但是当实例已存在时,您将返回该实例。这可以保证只创建一个连接。有很多这样的实现,尝试使用固定数量的连接,而不仅仅是一个。