我有一个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();
答案 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时,您创建一个新实例,但是当实例已存在时,您将返回该实例。这可以保证只创建一个连接。有很多这样的实现,尝试使用固定数量的连接,而不仅仅是一个。