c # genereic sql context patameter

0

У меня есть mssql-context-класс для легкого доступа к базе данных. Он содержит функцию для вставки datarows, которая выглядит так:

public int? Insert(string tableName, Action<SqlParameterCollection> actionSqlParameterCollection)
{
    using (var sqlConnection = new SqlConnection(ConnectionString))
    {
        sqlConnection.Open();

        using (var sqlCommand = sqlConnection.CreateCommand())
        {
            var commandText = $"insert into {tableName} (@columns) output inserted.id values (@values)";

            var valueBuilder = new StringBuilder();
            var columnBuilder = new StringBuilder();

            actionSqlParameterCollection?.Invoke(sqlCommand.Parameters); //Fill the parameters from outside with some values

            foreach (SqlParameter parameter in sqlCommand.Parameters)
            {
                valueBuilder.Append($",@{parameter.ParameterName}");
                columnBuilder.Append($",{parameter.ParameterName}");
            }

            commandText = commandText.Replace("@values", valueBuilder.ToString().Substring(1));
            commandText = commandText.Replace("@columns", columnBuilder.ToString().Substring(1));


            sqlCommand.CommandText = commandText;

            object result = sqlCommand.ExecuteScalar();

            return (int?)result;
        }
    }
}

Вызов этого будет выглядеть примерно так:

var context = MsSqlContext.CreateFrom("some_connectionstring");

context.Insert("myTable", parameters => {
    parameters.AddWithValue("foo_1", "bar_1");
    parameters.AddWithValue("foo_2", "bar_2");
});

Теперь я хочу создать общий SQL-контекст-класс, который также может обрабатывать базы данных mysql. Вставка-функция выглядит так:

public int? Insert(string tableName, Action<IDataParameterCollection> actionParameterCollection)
{
    using (var connection = this.CreateConnection())
    {
        using (var command = connection.CreateCommand())
        {
            var commandText = $"insert into {tableName} (@field) values (@values)";

            var valueBuilder = new StringBuilder();
            var columnBuilder = new StringBuilder();

            actionParameterCollection?.Invoke(command.Parameters); 

            foreach (IDbDataParameter parameter in command.Parameters)
            {
                valueBuilder.Append($",@{parameter.ParameterName}");
                columnBuilder.Append($",{parameter.ParameterName}");
            }

            commandText = commandText.Replace("@values", valueBuilder.ToString().Substring(1));
            commandText = commandText.Replace("@columns", columnBuilder.ToString().Substring(1));


            command.CommandText = commandText;

            object result = command.ExecuteScalar();

            return (int?)result;

        }
    }
}

Когда я пытаюсь вызвать функцию, она выглядит так:

var context = SqlContext.CreateFrom(SqlProvider.MySql, "Server=localhost;Database=4713_demo;Uid=root;Pwd=;");

context.Insert("my_table", parameters =>
{
    parameters.Add(?); //It expects an object
});

Моя проблема в том, что вы не хотите делать что-то вроде

context.Insert("my_table", parameters =>
{
    parameters.Add(context.CreateParameter("foo","bar")); 
});

Я просто хочу передать parametername и parametervalue. сам контекстный класс знает своего провайдера и должен создать параметр. Как это сделать?

Теги:
sql-server
generics

1 ответ

0
Лучший ответ

Решение, с которым я столкнулся, - это класс SqlParameterizer.

public class SqlParameterizer
{
    private SqlProvider Provider { get; set; }
    private List<IDbDataParameter> ParameterList { get; set; }

    public SqlParameterizer(SqlProvider sqlProvider)
    {
        this.Provider = sqlProvider;
        this.ParameterList = new List<IDbDataParameter>();
    }


    public void Add(string parameterName, object parameterValue)
    {
        switch(this.Provider)
        {
            case SqlProvider.MsSql:
                this.ParameterList.Add(new SqlParameter(parameterName, parameterValue));
                break;
            case SqlProvider.MySql:
                this.ParameterList.Add(new MySqlParameter(parameterName, parameterValue));
                break;
            case SqlProvider.OracleSql:
                throw new Exception($"SqlProvider '{this.Provider}' not supported yet...");
            default:
                throw new Exception($"Unknown SqlProvider '{this.Provider}'");
        }
    }
    public IDbDataParameter[] GetParameters()
    {
        return ParameterList.ToArray();
    }


}

Использование этого класса будет выглядеть так:

var commandText = $"insert into {tableName} (@columns) values (@values)";

var valueBuilder = new StringBuilder();
var columnBuilder = new StringBuilder();
var parameterizer = new SqlParameterizer(this.Provider);

actionValueParameterizer?.Invoke(parameterizer);

foreach(IDbDataParameter parameter in parameterizer.GetParameters())
{
    command.Parameters.Add(parameter);
    valueBuilder.Append($",@{parameter.ParameterName}");
    columnBuilder.Append($",{parameter.ParameterName}");
}

commandText = commandText.Replace("@values", valueBuilder.ToString().Substring(1));
commandText = commandText.Replace("@columns", columnBuilder.ToString().Substring(1));

command.CommandText = commandText;

command.ExecuteNonQuery();

Вызов моей функции вставки:

context.Insert("some_table", parameterizer =>
{
    parameterizer.Add("some_column", "some_value");
});

Ещё вопросы

Сообщество Overcoder
Наверх
Меню