private static readonly string dataProvider = ConfigurationManager.AppSettings.Get("Provider");
private static readonly DbProviderFactory factory = DbProviderFactories.GetFactory(dataProvider);
private static readonly string connectionString = ConfigurationManager.ConnectionStrings[dataProvider].ConnectionString;
/// <summary>
/// Executes Update statements in the database.
/// </summary>
/// <param name="sql">Sql statement.</param>
/// <returns>Number of rows affected.</returns>
public static int Update(string sql)
{
using (DbConnection connection = factory.CreateConnection())
{
connection.ConnectionString = connectionString;
using (DbCommand command = factory.CreateCommand())
{
command.Connection = connection;
command.CommandText = sql;
connection.Open();
return command.ExecuteNonQuery();
}
}
}
我需要帮助重写这个,以便它可以与存储过程一起使用。 (通过sproc名称和params) 有谁知道我应该怎么做呢? 编辑:我遇到问题的领域是试图找出填写参数的方法。
由于
答案 0 :(得分:10)
您已经需要参数,而不管您是否正在实施存储过程。
现在,您可以使用SELECT * FROM Table WHERE ID = @ID
之类的查询调用您的代码,在这种情况下,您需要传递Dictionary<string,object> params
。让您的代码填入您已有命令的Parameters集合,并在担心存储过程之前对其进行测试。
一旦有效,你应该简单地创建一个重载,接受一个bool,说这是一个存储过程,然后用它来设置命令的CommandType属性。
编辑:这是我将如何重构
第1步:概括更新
除了名称之外,Update方法没有任何特殊之处可以阻止它用于其他非查询操作。所以:
/// <summary>
/// Executes Update statements in the database.
/// </summary>
/// <param name="sql">Sql statement.</param>
/// <returns>Number of rows affected.</returns>
public static int Update(string sql)
{
return NonQuery(sql);
}
public static int NonQuery(string sql)
{
using (DbConnection connection = factory.CreateConnection())
{
connection.ConnectionString = connectionString;
using (DbCommand command = factory.CreateCommand())
{
command.Connection = connection;
command.CommandText = sql;
connection.Open();
return command.ExecuteNonQuery();
}
}
}
第2步:参数怎么样?
您当前的代码甚至无法处理使用参数的UPDATE查询,所以让我们开始修复它。首先,如果没有指定参数,请确保它仍然有效:
public static int NonQuery(string sql)
{
Dictionary<string, object> parameters = null;
if (parameters == null)
{
parameters = new Dictionary<string, object>();
}
using (DbConnection connection = factory.CreateConnection())
{
connection.ConnectionString = connectionString;
using (DbCommand command = factory.CreateCommand())
{
command.Connection = connection;
command.CommandText = sql;
foreach (KeyValuePair<string, object> p in parameters)
{
var parameter = command.CreateParameter();
parameter.ParameterName = p.Key;
parameter.Value = p.Value;
command.Parameters.Add(parameter);
}
connection.Open();
return command.ExecuteNonQuery();
}
}
}
一旦有效,将参数提升为参数。这不会影响Update
的任何现有呼叫者:
/// <summary>
/// Executes Update statements in the database.
/// </summary>
/// <param name="sql">Sql statement.</param>
/// <returns>Number of rows affected.</returns>
public static int Update(string sql)
{
return NonQuery(sql, null);
}
public static int NonQuery(string sql, Dictionary<string, object> parameters)
此时,使用参数化查询测试NonQuery。一旦有效,创建一个接受参数的Update重载:
/// <summary>
/// Executes Update statements in the database.
/// </summary>
/// <param name="sql">Sql statement.</param>
/// <returns>Number of rows affected.</returns>
public static int Update(string sql)
{
return NonQuery(sql, null);
}
/// <summary>
/// Executes Update statements in the database.
/// </summary>
/// <param name="sql">Sql statement.</param>
/// <param name="parameters">Name/value dictionary of parameters</param>
/// <returns>Number of rows affected.</returns>
public static int Update(string sql, Dictionary<string, object> parameters)
{
return NonQuery(sql, parameters);
}
第3步:将存储过程纳入考虑
存储过程的处理方式几乎没有什么区别。您已经得到的内容隐含如下:
using (DbCommand command = factory.CreateCommand())
{
command.Connection = connection;
command.CommandText = sql;
command.CommandType = CommandType.Text;
因此,请使用CommandType.Text并将其提升为重载中的参数:
public static int NonQuery(string sql, Dictionary<string, object> parameters)
{
return NonQuery(sql, CommandType.Text, parameters);
}
public static int NonQuery(string sql, CommandType commandType, Dictionary<string, object> parameters)
最后,如果您愿意,请更新Update
:
/// <summary>
/// Executes Update statements in the database.
/// </summary>
/// <param name="sql">Sql statement.</param>
/// <param name="parameters">Name/value dictionary of parameters</param>
/// <returns>Number of rows affected.</returns>
public static int Update(string sql, Dictionary<string, object> parameters)
{
return Update(sql, CommandType.Text, parameters);
}
/// <summary>
/// Executes Update statements in the database.
/// </summary>
/// <param name="sql">Sql statement.</param>
/// <param name="commandType">CommandType.Text or CommandType.StoredProcedure</param>
/// <param name="parameters">Name/value dictionary of parameters</param>
/// <returns>Number of rows affected.</returns>
public static int Update(string sql, CommandType commandType, Dictionary<string, object> parameters)
{
return NonQuery(sql, parameters);
}
当然,作为读者的最后练习,您可以使用对NonQuery的调用替换所有Update调用,并完全摆脱更新。
当然,这种简单的技术不处理输出参数,或者需要指定参数的DbType的情况。为此,您需要接受某种ParameterCollection。
答案 1 :(得分:0)
您可以添加3个参数:
string SchemaName
- 存储数据库架构的名称string StoredProcName
- 存储存储过程的名称List<Parameter>
- 存储过程参数列表答案 2 :(得分:0)
使用重载,例如
public static int Update(string storedProc, Dictionary<string,string> params)
{
...
}
答案 3 :(得分:0)
我使用界面和泛型做类似的事情。
实施例
using System.Data.SqlClient;
public interface IParameter<T> where T : IEntity<T>
{
void Populate(SqlParameterCollection parameters, T entity);
}
实现接口的类 使用System.Data; 使用System.Data.SqlClient;
public class UserParameter : IParameter<User>
{
public void Populate(SqlParameterCollection parameters, User entity)
{
parameters.Add("@ID", SqlDbType.UniqueIdentifier).Value = entity.Id;
parameters.Add("@Name", SqlDbType.NVarChar, 255).Value = entity.Name;
parameters.Add("@EmailAddress", SqlDbType.NVarChar, 255).Value = entity.EmailAddress;
}
}
然后我们有执行更新的方法
public void Update<T>(string prefix, IParameter<T> parameters, T entity)
where T : class, IEntity<T>
{
using (var connection = this.Connection())
{
using (var command = new SqlCommand(string.Format("dbo.{0}_Update", prefix), connection))
{
command.CommandType = CommandType.StoredProcedure;
parameters.Populate(command.Parameters, entity);
connection.Open();
command.ExecuteNonQuery();
connection.Close();
}
}
}
然后我做了一些像
这样的事情更新(“用户”,新的UserParameter(),值);
我也从读者值中填充实体。
答案 4 :(得分:0)
您可能会遇到困难,具体取决于您计划放置此环境的环境。
如果我理解正确,你想保留函数签名(单个字符串参数),但如果字符串中的第一个单词不是“UPDATE”,则处理它不同。例如,此字符串应执行名为UpdateTable1的存储过程,其中包含四个参数:
UpdateTable1 NULL, A5KMI, "New description", #5/10/2009#
或类似的东西。
问题是你需要在字符串其余部分的参数之间使用分隔符。为此,你必须将字符串分解为标记,这可能会变得非常棘手。
所以替代方法是在整个字符串前添加命令EXEC,将整个事物设置为CommandText属性,然后调用其中一个Execute方法。
我不喜欢这个,它确实为您打开了SQL注入漏洞。如果可能的话,使用其他人已经回答的重载方法,并让调用者将参数拆分成某种集合。