|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Data;
|
|
|
|
|
using System.Data.Common;
|
|
|
|
|
using System.Data.SqlClient;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
|
|
|
|
|
namespace ZeroLevel.MsSql
|
|
|
|
|
{
|
|
|
|
|
public class SqlDbProvider :
|
|
|
|
|
IDbProvider
|
|
|
|
|
{
|
|
|
|
|
#region Fields
|
|
|
|
|
private readonly SqlDbConnectionFactory _factory;
|
|
|
|
|
private const int Timeout = 60000;
|
|
|
|
|
|
|
|
|
|
public string ConnectionString
|
|
|
|
|
{
|
|
|
|
|
get { return _factory.ConnectionString; }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public string Server
|
|
|
|
|
{
|
|
|
|
|
get { return _factory.Server; }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public string Base
|
|
|
|
|
{
|
|
|
|
|
get { return _factory.Base; }
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region .Ctor
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Конструктор.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public SqlDbProvider(SqlDbConnectionFactory factory)
|
|
|
|
|
{
|
|
|
|
|
_factory = factory;
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region ExecuteNonResult
|
|
|
|
|
public void ExecuteNonResult(IEnumerable<ZSqlCommand> commands)
|
|
|
|
|
{
|
|
|
|
|
using (DbConnection connection = _factory.CreateConnection())
|
|
|
|
|
{
|
|
|
|
|
foreach (var zcmd in commands)
|
|
|
|
|
{
|
|
|
|
|
using (var cmd = CreateCommand(connection, zcmd.Query, zcmd.Parameters, Timeout))
|
|
|
|
|
{
|
|
|
|
|
cmd.ExecuteNonQuery();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
connection.Close();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public int ExecuteNonResult(string query)
|
|
|
|
|
{
|
|
|
|
|
return ExecuteNonResult(query, null);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public int ExecuteNonResult(string query, DbParameter[] par)
|
|
|
|
|
{
|
|
|
|
|
using (DbConnection connection = _factory.CreateConnection())
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
using (var cmd = CreateCommand(connection, query, par, Timeout))
|
|
|
|
|
{
|
|
|
|
|
return cmd.ExecuteNonQuery();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
finally
|
|
|
|
|
{
|
|
|
|
|
connection.Close();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public T Insert<T>(string insert_query, SqlParameter[] par)
|
|
|
|
|
{
|
|
|
|
|
DbConnection connection = _factory.CreateConnection();
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
using (var cmd = CreateCommand(connection, insert_query, par, Timeout))
|
|
|
|
|
{
|
|
|
|
|
var result = cmd.ExecuteScalar();
|
|
|
|
|
return (T)result;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
finally
|
|
|
|
|
{
|
|
|
|
|
connection.Close();
|
|
|
|
|
connection.Dispose();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region ExecuteQueryDataTable
|
|
|
|
|
public DataTable ExecuteQueryDataTable(string query)
|
|
|
|
|
{
|
|
|
|
|
var ds = ExecuteQuerySqlDataSet(query);
|
|
|
|
|
if (ds != null && ds.Tables.Count > 0)
|
|
|
|
|
{
|
|
|
|
|
return ds.Tables[0];
|
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public DataTable ExecuteQueryDataTable(string query, DbParameter[] par)
|
|
|
|
|
{
|
|
|
|
|
var ds = ExecuteQuerySqlDataSet(query, par);
|
|
|
|
|
if (ds != null && ds.Tables.Count > 0)
|
|
|
|
|
{
|
|
|
|
|
return ds.Tables[0];
|
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region ExecuteQuerySqlDataSet
|
|
|
|
|
public DataSet ExecuteQuerySqlDataSet(string query)
|
|
|
|
|
{
|
|
|
|
|
var ds = new DataSet("DataSet");
|
|
|
|
|
using (var connection = _factory.CreateConnection())
|
|
|
|
|
{
|
|
|
|
|
using (var cmd = CreateCommand(connection, query, null, Timeout))
|
|
|
|
|
{
|
|
|
|
|
using (var da = new SqlDataAdapter(cmd))
|
|
|
|
|
{
|
|
|
|
|
da.Fill(ds);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
connection.Close();
|
|
|
|
|
}
|
|
|
|
|
return ds;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public DataSet ExecuteQuerySqlDataSet(string query, DbParameter[] par)
|
|
|
|
|
{
|
|
|
|
|
var ds = new DataSet("DataSet");
|
|
|
|
|
using (var connection = _factory.CreateConnection())
|
|
|
|
|
{
|
|
|
|
|
using (var cmd = CreateCommand(connection, query, par, Timeout))
|
|
|
|
|
{
|
|
|
|
|
using (var da = new SqlDataAdapter(cmd))
|
|
|
|
|
{
|
|
|
|
|
da.Fill(ds);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
connection.Close();
|
|
|
|
|
}
|
|
|
|
|
return ds;
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region ExecuteScalar
|
|
|
|
|
public object ExecuteScalar(string query)
|
|
|
|
|
{
|
|
|
|
|
using (var connection = _factory.CreateConnection())
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
using (var cmd = CreateCommand(connection, query, null, Timeout))
|
|
|
|
|
{
|
|
|
|
|
return cmd.ExecuteScalar();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
finally
|
|
|
|
|
{
|
|
|
|
|
connection.Close();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public object ExecuteScalar(string query, DbParameter[] par)
|
|
|
|
|
{
|
|
|
|
|
using (var connection = _factory.CreateConnection())
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
using (var cmd = CreateCommand(connection, query, par, Timeout))
|
|
|
|
|
{
|
|
|
|
|
return cmd.ExecuteScalar();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
finally
|
|
|
|
|
{
|
|
|
|
|
connection.Close();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region ExecuteStoredProcedure
|
|
|
|
|
public int ExecProcedure(string name)
|
|
|
|
|
{
|
|
|
|
|
using (var connection = _factory.CreateConnection())
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
using (var command = new SqlCommand(name, connection)
|
|
|
|
|
{
|
|
|
|
|
CommandType = CommandType.StoredProcedure
|
|
|
|
|
})
|
|
|
|
|
{
|
|
|
|
|
command.CommandTimeout = 300000;
|
|
|
|
|
return command.ExecuteNonQuery();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
finally
|
|
|
|
|
{
|
|
|
|
|
connection.Close();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
public DbReader ExecuteReader(string query, DbParameter[] par)
|
|
|
|
|
{
|
|
|
|
|
var connection = _factory.CreateConnection();
|
|
|
|
|
return new DbReader(connection, CreateCommand(connection, query, par, Timeout));
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#region LazySelect
|
|
|
|
|
public void LazySelect(string query, DbParameter[] par, Func<DbDataReader, bool> readHandler)
|
|
|
|
|
=> LazySelect(query, par, readHandler, Timeout);
|
|
|
|
|
|
|
|
|
|
public void LazySelect(string query, DbParameter[] par, Func<DbDataReader, bool> readHandler, int timeout = Timeout)
|
|
|
|
|
{
|
|
|
|
|
using (var connection = _factory.CreateConnection())
|
|
|
|
|
{
|
|
|
|
|
using (var cmd = CreateCommand(connection, query, par, Timeout))
|
|
|
|
|
{
|
|
|
|
|
using (SqlDataReader reader = cmd.ExecuteReader(CommandBehavior.CloseConnection))
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
while (reader.Read())
|
|
|
|
|
{
|
|
|
|
|
if (false == readHandler(reader))
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
Log.Error(ex, "Error executing query {0}.", cmd.CommandText);
|
|
|
|
|
}
|
|
|
|
|
finally
|
|
|
|
|
{
|
|
|
|
|
// Always call Close when done reading.
|
|
|
|
|
reader.Close();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void LazySelectWithParameters(string query, IEnumerable<KeyValuePair<string, object>> par, Func<DbDataReader, bool> readHandler, int timeout = Timeout)
|
|
|
|
|
{
|
|
|
|
|
using (var connection = _factory.CreateConnection())
|
|
|
|
|
{
|
|
|
|
|
using (var cmd = CreateCommand(connection, query, null, Timeout))
|
|
|
|
|
{
|
|
|
|
|
if (par != null && par.Any())
|
|
|
|
|
{
|
|
|
|
|
foreach (var p in par)
|
|
|
|
|
{
|
|
|
|
|
cmd.Parameters.AddWithValue(p.Key, p.Value);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
using (SqlDataReader reader = cmd.ExecuteReader(CommandBehavior.CloseConnection))
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
while (reader.Read())
|
|
|
|
|
{
|
|
|
|
|
if (false == readHandler(reader))
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
Log.Error(ex, "Error executing query {0}.", cmd.CommandText);
|
|
|
|
|
}
|
|
|
|
|
finally
|
|
|
|
|
{
|
|
|
|
|
// Always call Close when done reading.
|
|
|
|
|
reader.Close();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region ExistsTable
|
|
|
|
|
private const string QueryExistsTable = @"IF OBJECT_ID (N'[{0}]', N'U') IS NOT NULL SELECT 1 AS res ELSE SELECT 0 AS res";
|
|
|
|
|
public bool ExistsTable(string tableName)
|
|
|
|
|
{
|
|
|
|
|
return Convert.ToInt32(ExecuteScalar(String.Format(QueryExistsTable, tableName))) == 1;
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Commands
|
|
|
|
|
private static SqlParameter[] ProcessParameters(DbParameter[] par)
|
|
|
|
|
{
|
|
|
|
|
if (par != null)
|
|
|
|
|
{
|
|
|
|
|
var result = new SqlParameter[par.Length];
|
|
|
|
|
for (int i = 0; i < par.Length; i++)
|
|
|
|
|
{
|
|
|
|
|
if (par[i] is SqlParameter)
|
|
|
|
|
{
|
|
|
|
|
result[i] = (SqlParameter)par[i];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
result[i] = new SqlParameter(par[i].ParameterName,
|
|
|
|
|
par[i].Value ?? DBNull.Value);
|
|
|
|
|
result[i].Size = par[i].Size;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
return new SqlParameter[0];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static SqlCommand CreateCommand(DbConnection connection, string query, DbParameter[] parameters, int timeout)
|
|
|
|
|
{
|
|
|
|
|
var command = connection.CreateCommand();
|
|
|
|
|
command.CommandText = query;
|
|
|
|
|
command.CommandType = CommandType.Text;
|
|
|
|
|
if (timeout > 0)
|
|
|
|
|
command.CommandTimeout = timeout;
|
|
|
|
|
if (parameters != null && parameters.Length > 0)
|
|
|
|
|
command.Parameters.AddRange(ProcessParameters(parameters));
|
|
|
|
|
return (SqlCommand)command;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region SQL Server execute plan reset
|
|
|
|
|
private const string CLEAN_PLAN_CACHEE_QUERY = "DBCC FREEPROCCACHE WITH NO_INFOMSGS;";
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Выполняет удаление всех элементов из кэша планов.
|
|
|
|
|
/// Применимо для ускорения работы SQL Server, при очистке кэша создаются новые планы
|
|
|
|
|
/// исполнения для новых значений запросов.
|
|
|
|
|
/// </summary>
|
|
|
|
|
public void CleanPlanCachee()
|
|
|
|
|
{
|
|
|
|
|
using (var connection = _factory.CreateConnection())
|
|
|
|
|
{
|
|
|
|
|
using (var cmd = CreateCommand(connection, CLEAN_PLAN_CACHEE_QUERY,
|
|
|
|
|
null, Timeout))
|
|
|
|
|
{
|
|
|
|
|
cmd.ExecuteNonQuery();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
#region Static methods
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Создает базу данных
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="server">Сервер</param>
|
|
|
|
|
/// <param name="database">Название базы данных</param>
|
|
|
|
|
public static void CreateDatabase(string server, string database, string login, string password)
|
|
|
|
|
{
|
|
|
|
|
if (string.IsNullOrEmpty(server))
|
|
|
|
|
{
|
|
|
|
|
throw new ArgumentException("Не указано имя сервера");
|
|
|
|
|
}
|
|
|
|
|
if (string.IsNullOrEmpty(database))
|
|
|
|
|
{
|
|
|
|
|
throw new ArgumentException("Не указано имя базы данных");
|
|
|
|
|
}
|
|
|
|
|
using (var connection = new SqlConnection(SqlDbConnectionFactory.BuildConnectionString(server, "master", login, password)))
|
|
|
|
|
{
|
|
|
|
|
connection.Open();
|
|
|
|
|
using (var command = connection.CreateCommand())
|
|
|
|
|
{
|
|
|
|
|
command.CommandText = String.Format("CREATE DATABASE {0}", database);
|
|
|
|
|
command.ExecuteNonQuery();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Выполняет проверку существования базы данных с указанным именем
|
|
|
|
|
/// </summary>
|
|
|
|
|
public static bool CheckDatabaseExists(string serverName, string databaseName)
|
|
|
|
|
{
|
|
|
|
|
string sqlExistsDBQuery;
|
|
|
|
|
bool result = false;
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
using (var tmpConn = new SqlConnection(String.Format("server={0};Trusted_Connection=yes", serverName)))
|
|
|
|
|
{
|
|
|
|
|
tmpConn.Open();
|
|
|
|
|
sqlExistsDBQuery = string.Format("SELECT database_id FROM sys.databases WHERE Name = '{0}'", databaseName);
|
|
|
|
|
using (SqlCommand sqlCmd = new SqlCommand(sqlExistsDBQuery, tmpConn))
|
|
|
|
|
{
|
|
|
|
|
object resultObj = sqlCmd.ExecuteScalar();
|
|
|
|
|
int databaseID = 0;
|
|
|
|
|
if (resultObj != null)
|
|
|
|
|
{
|
|
|
|
|
int.TryParse(resultObj.ToString(), out databaseID);
|
|
|
|
|
}
|
|
|
|
|
result = (databaseID > 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
Log.Error(ex, "Сбой при попытке подключения к серверу {0} и проверке наличия базы данных {1}",
|
|
|
|
|
serverName, databaseName);
|
|
|
|
|
result = false;
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Удаляет базу данных
|
|
|
|
|
/// </summary>
|
|
|
|
|
public static void DropDatabase(string server, string database, string login, string password)
|
|
|
|
|
{
|
|
|
|
|
if (string.IsNullOrEmpty(server))
|
|
|
|
|
{
|
|
|
|
|
throw new ArgumentException("Не указано имя сервера");
|
|
|
|
|
}
|
|
|
|
|
if (string.IsNullOrEmpty(database))
|
|
|
|
|
{
|
|
|
|
|
throw new ArgumentException("Не указано имя базы данных");
|
|
|
|
|
}
|
|
|
|
|
using (var connection = new SqlConnection(SqlDbConnectionFactory.BuildConnectionString(server, "master", login, password)))
|
|
|
|
|
{
|
|
|
|
|
connection.Open();
|
|
|
|
|
using (var command = connection.CreateCommand())
|
|
|
|
|
{
|
|
|
|
|
command.CommandText = String.Format("ALTER DATABASE {0} SET SINGLE_USER WITH ROLLBACK IMMEDIATE;\r\nDROP DATABASE [{1}]", database, database);
|
|
|
|
|
command.ExecuteNonQuery();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endregion
|
|
|
|
|
}
|
|
|
|
|
}
|