Stored procedures DAL(包括参数)的通用程序执行方法

Stored procedures DAL(包括参数)的通用程序执行方法,stored-procedures,ado.net,data-access-layer,sqlparameter,Stored Procedures,Ado.net,Data Access Layer,Sqlparameter,我试图在数据访问层中创建一个“通用”方法,该方法在Sql Server中执行一个传递的存储过程,并获取SqlParameters的列表/数组/集合,以便在代码的其他部分中更轻松地使用存储过程调用(无需关心连接、命令对象等) 目标是这样的: int iAffectedRows = dal.RunProcedure("dbo.mySP", parameters); public class DataAccess { private ConnectionStringSettings _set

我试图在数据访问层中创建一个“通用”方法,该方法在Sql Server中执行一个传递的存储过程,并获取SqlParameters的列表/数组/集合,以便在代码的其他部分中更轻松地使用存储过程调用(无需关心连接、命令对象等)

目标是这样的:

int iAffectedRows = dal.RunProcedure("dbo.mySP", parameters);
public class DataAccess
{
    private ConnectionStringSettings _settings;

    public DataAccess(ConnectionStringSettings settings)
    {
        _settings = settings;
    }

    public int RunProcedure(string name, dynamic parameters)
    {
        using (var conn = CreateConnection())
        using (var command = CreateCommand(conn, name, parameters))
        {
            return command.ExecuteNonQuery();
        }
    }

    private DbConnection CreateConnection()
    {
        var factory = DbProviderFactories.GetFactory(_settings.ProviderName);
        var connection = factory.CreateConnection();
        connection.ConnectionString = _settings.ConnectionString;
        connection.Open();
        return connection;
    }

    private DbCommand CreateCommand(DbConnection conn, string commandText,
        object parameters)
    {
        var cmd = conn.CreateCommand();
        cmd.CommandText = commandText;
        cmd.CommandType = CommandType.StoredProcedure;
        foreach(PropertyInfo parameter in parameters.GetType().GetProperties())
        {
            var commandParameter = cmd.CreateParameter();
            commandParameter.ParameterName = "@" + parameter.Name;
            commandParameter.Value = parameter.GetValue(parameters);
            cmd.Parameters.Add(commandParameter);
        }
        return cmd;
    }
}
dal.RunProcedure("dbo.mySP", new { 
    Parameter1 = value1, 
    Parameter2 = value2
});
当然,参数应该在前面定义,但不包括类型。我希望使用的
AddwithValue()
方法创建它们

看起来这是不可能的,因为SqlParameterCollection类无法实例化。看看这个


有人知道如何创建它吗?

最好不要发送
DbParameterCollection
SqlParameterCollection
),因为它与您试图抽象的ADO.NET基础结构紧密耦合(您已经发现)。最好将自己的参数表示映射到方法内部的集合

您可以使用以下方法解决此问题:

int iAffectedRows = dal.RunProcedure("dbo.mySP", parameters);
public class DataAccess
{
    private ConnectionStringSettings _settings;

    public DataAccess(ConnectionStringSettings settings)
    {
        _settings = settings;
    }

    public int RunProcedure(string name, dynamic parameters)
    {
        using (var conn = CreateConnection())
        using (var command = CreateCommand(conn, name, parameters))
        {
            return command.ExecuteNonQuery();
        }
    }

    private DbConnection CreateConnection()
    {
        var factory = DbProviderFactories.GetFactory(_settings.ProviderName);
        var connection = factory.CreateConnection();
        connection.ConnectionString = _settings.ConnectionString;
        connection.Open();
        return connection;
    }

    private DbCommand CreateCommand(DbConnection conn, string commandText,
        object parameters)
    {
        var cmd = conn.CreateCommand();
        cmd.CommandText = commandText;
        cmd.CommandType = CommandType.StoredProcedure;
        foreach(PropertyInfo parameter in parameters.GetType().GetProperties())
        {
            var commandParameter = cmd.CreateParameter();
            commandParameter.ParameterName = "@" + parameter.Name;
            commandParameter.Value = parameter.GetValue(parameters);
            cmd.Parameters.Add(commandParameter);
        }
        return cmd;
    }
}
dal.RunProcedure("dbo.mySP", new { 
    Parameter1 = value1, 
    Parameter2 = value2
});
可使用如下语法调用:

int iAffectedRows = dal.RunProcedure("dbo.mySP", parameters);
public class DataAccess
{
    private ConnectionStringSettings _settings;

    public DataAccess(ConnectionStringSettings settings)
    {
        _settings = settings;
    }

    public int RunProcedure(string name, dynamic parameters)
    {
        using (var conn = CreateConnection())
        using (var command = CreateCommand(conn, name, parameters))
        {
            return command.ExecuteNonQuery();
        }
    }

    private DbConnection CreateConnection()
    {
        var factory = DbProviderFactories.GetFactory(_settings.ProviderName);
        var connection = factory.CreateConnection();
        connection.ConnectionString = _settings.ConnectionString;
        connection.Open();
        return connection;
    }

    private DbCommand CreateCommand(DbConnection conn, string commandText,
        object parameters)
    {
        var cmd = conn.CreateCommand();
        cmd.CommandText = commandText;
        cmd.CommandType = CommandType.StoredProcedure;
        foreach(PropertyInfo parameter in parameters.GetType().GetProperties())
        {
            var commandParameter = cmd.CreateParameter();
            commandParameter.ParameterName = "@" + parameter.Name;
            commandParameter.Value = parameter.GetValue(parameters);
            cmd.Parameters.Add(commandParameter);
        }
        return cmd;
    }
}
dal.RunProcedure("dbo.mySP", new { 
    Parameter1 = value1, 
    Parameter2 = value2
});
如果只想支持
SqlClient
,则可以大大简化代码


但是不要自己滚动,而是使用现成的稳定库,例如。

我最终得到了以下解决方案:

SqlParameter[] parameters = {
new SqlParameter("@p1", SqlDbType.Int) { Value = 999},
new SqlParameter("@p2",  SqlDbType.Char, 30, "source") { Value = "test"}
}; 
da.RunProcedure("[dbo].[SP1]", parameters, out rowsAffected); 
RunProcedure接受
IDataParameter[]parameters
并将其转发给命令生成器方法,该方法将每个参数添加到我的SqlCommand对象的SqlParameters属性中:

private static SqlCommand BuildQueryCommand(string storedProcName, IDataParameter[] parameters)
        {
            SqlCommand command = new SqlCommand( storedProcName, GetDBConnection() );
            command.CommandType = CommandType.StoredProcedure;

            if (parameters != null)
            {
                foreach (SqlParameter parameter in parameters)
                {
                    command.Parameters.Add( parameter );
                }
            }
            return command;    
        }

这很好,通过这种方式,我可以用一行代码添加每个参数(这是我的目的地#1),包括SqlParameter的所有可用属性(如果需要,请使用SqlDBType,这取决于用户)。

PropertyInfo
系统中可用。反射
。使用系统反射添加
到您的代码。是的,对不起,我没有意识到反射。但是GetValue()方法仍然不允许只有1个参数。如果您使用的是.NET 2.0,我使用的重载不存在,您必须向
GetValue
-
parameter.GetValue(parameters,null)
。是的,2.0。我使用了您的示例并创建了一个有效且易于使用的解决方案。对此有何评论/想法?如果你觉得这是一种贡献,请将其作为单独的答案发布,而不是在你的问题中。作为方法的用户,如果传递给方法的
SqlParameter
的所有属性(如DbType等)都没有在查询中实际使用,我会感到很困惑。我觉得如果您只对名称和值感兴趣,那么最好使用另一种类型。要么像在我的答案中一样,要么使用另一个
KeyValuePair
类型。如果这是你找到解决方案的原因,请随意投票/接受我的答案。