C# 如何重构此方法?
它工作正常,但我想把它缩短,以便更容易理解。如何重构它?为每个命令(在C# 如何重构此方法?,c#,C#,它工作正常,但我想把它缩短,以便更容易理解。如何重构它?为每个命令(在if语句中)创建字符串(或字符串数组),如果字符串不为空,则随后运行sql [注] 在任何情况下都不会关闭连接 [/note]为了让它更容易理解,您可能需要重构它,以便更容易测试 在这种情况下,可能需要去掉ConnectionClass单例(而是使用IoC并注入连接工厂)和MessageBox(例如,抛出异常并让周围的代码确定如何显示此消息)您可以使用参数,当您不想更新字段时,可以将其设置为NULL: private void
if
语句中)创建字符串(或字符串数组),如果字符串不为空,则随后运行sql
[注]在任何情况下都不会关闭连接
[/note]为了让它更容易理解,您可能需要重构它,以便更容易测试
在这种情况下,可能需要去掉
ConnectionClass
单例(而是使用IoC并注入连接工厂)和MessageBox(例如,抛出异常并让周围的代码确定如何显示此消息)您可以使用参数,当您不想更新字段时,可以将其设置为NULL
:
private void Update_Record_Click(object sender, EventArgs e)
{
ConnectionClass.OpenConnection();
if (textBox4.Text == "" && textBox2.Text == "")
{
MessageBox.Show("No value entred for update.");
}
else if (textBox4.Text != "" && textBox2.Text != "")
{
SqlCommand cmd = new SqlCommand("update medicinerecord set quantity='" + textBox2.Text + "' where productid='"+comboBox1.Text+"'", ConnectionClass.OpenConnection());
cmd.ExecuteNonQuery();
cmd = new SqlCommand("update myrecord set price='" + textBox4.Text + "' where productid='" + comboBox1.Text + "'", ConnectionClass.OpenConnection());
cmd.ExecuteNonQuery();
ConnectionClass.CloseConnection();
}
else if (textBox2.Text != "")
{
SqlCommand cmd = new SqlCommand("update myrecord set quantity='" + textBox2.Text + "' where productid='" + comboBox1.Text + "'", ConnectionClass.OpenConnection());
cmd.ExecuteNonQuery();
ConnectionClass.CloseConnection();
}
else if (textBox4.Text != "")
{
SqlCommand cmd = new SqlCommand("update myrecord set price='" + textBox4.Text + "' where productid='" + comboBox1.Text + "'", ConnectionClass.OpenConnection());
cmd.ExecuteNonQuery();
ConnectionClass.CloseConnection();
}
}
然后,根据文本字段,您可以使用command.Parameters.AddWithValue
方法执行单个命令。对NULL
使用DBNull.Value
。即使不更改结构,也应该这样做以防止SQL注入攻击
干杯,马蒂亚斯你可以看到
UPDATE myrecord SET price = ISNULL(@price, price) -- MSSQL
是reduntant,那么为什么不将其移动到最后一个之后呢?如果作用域不在,则将其移动。使代码“小”可能不是使其可读或“易于理解”的最佳方法。我发现更简洁的代码比具有高质量变量、方法、属性、类名等的代码更难理解
我认为更严重的问题不是代码的大小,而是您容易受到SQL注入攻击这一事实
这是我很久以前写的一篇文章,你可能会发现它很有用:
我希望这能有所帮助。免责声明:根据Darin的建议,我稍微改变了他最初的解决方案。布朗医生
这段代码很大这一事实是最小的问题。在这里,SQL注入有更大的问题。您应该使用参数化查询来避免这种情况
因此,我首先将数据访问逻辑外部化为一个单独的方法:
cmd.ExecuteNonQuery();
ConnectionClass.CloseConnection();
然后:
public void UpdateMedicineRecordQuantity(string tableName, string attributeName, string productId, string attributeValue)
{
using (var conn = new SqlConnection("YOUR ConnectionString HERE"))
using (var cmd = conn.CreateCommand())
{
conn.Open();
cmd.CommandText = "UPDATE " + tableName + "SET " + attributeName+ " = @attributeValue where productid = @productid";
cmd.Parameters.AddWithValue("@attributeValue", attributeValue);
cmd.Parameters.AddWithValue("@productid", productId);
cmd.ExecuteNonQuery();
}
}
使用“tableName”和“attributeName”作为SQL的动态部分没有安全问题,只要您不让用户为这两个参数提供输入
您可以继续在其他情况下重用此方法。为什么不再创建一个方法:
string productId = comboBox1.Text;
string quantity = textBox2.Text;
UpdateMedicineRecordQuantity("medicinerecord", "quantity", productId, quantity);
您的代码正在等待SQL注入。请注意“ol Johnny Tables”。我对您的代码进行了一些简化和优化,并添加了一些注释
void ExecuteCommand(string sql)
{
SqlCommand cmd = new SqlCommand(sql);
cmd.ExecuteNonQuery();
ConnectionClass.CloseConnection();
}
如果只执行一行代码,可以通过删除条件语句(如if
)上的大括号立即简化代码。我为你做了这件事
在未首先转义任何用户输入的变量之前,不要使用字符串连接构建SQL语句。例如,更新我的记录集价格='“+textbox4.Text+”
。。至少应该是updatemyrecord set price='“+textbox4.Text.Replace(“'”,“”)
。以避免可能的攻击
与其测试.Text==“”
,通常更倾向于使用或在.NET 4上覆盖空字符串和空字符串
替换var
的任何显式类型的数据类型
最后,您可以简化此代码,方法是在验证未满足时立即返回(如前几行所示),并在验证发生后在此方法的顶部和底部指定一个OpenConnection()
和CloseConnection()
还修复了拼写错误!:)类似于if的语句(textBox4.Text==”&&textBox2.Text==”)
如果你不了解应用程序的特定部分在做什么,那就没有任何意义。在这种情况下,它们似乎每个代表一个值,并且至少其中一个应该包含合法操作的内容。研究SQL语句表明textBox2
是一个数量,而textBox4是一个价格。首先要将这些控件名称更改为更有意义的名称
其次,我将检查包装成具有更多描述性名称的方法:
private void Update_Record_Click(object sender, EventArgs e)
{
if (textBox4.Text == "" && textBox2.Text == "")
{
MessageBox.Show("No value entered for update.");
return;
}
ConnectionClass.OpenConnection();
var cmd = new SqlCommand("update medicinerecord set quantity='" + textBox2.Text + "' where productid='" + comboBox1.Text + "'", ConnectionClass.OpenConnection());
cmd.ExecuteNonQuery();
cmd = null;
if (textBox2.Text != "")
cmd = new SqlCommand("update myrecord set quantity='" + textBox2.Text + "' where productid='" + comboBox1.Text + "'", ConnectionClass.OpenConnection());
else if (textBox4.Text != "")
cmd = new SqlCommand("update myrecord set price='" + textBox4.Text + "' where productid='" + comboBox1.Text + "'", ConnectionClass.OpenConnection());
if (cmd != null) cmd.ExecuteNonQuery();
ConnectionClass.CloseConnection();
}
然后可以将if块重写为:
private bool HasPriceValue()
{
return !string.IsNullOrEmpty(textBox4.Text);
}
private bool HasQuantityValue()
{
return !string.IsNullOrEmpty(textBox2.Text);
}
通过这种方式,您不必在代码中重复SQL查询,阅读代码并理解其功能相当容易。下一步是重写SQL查询以使用参数而不是串联字符串(这会打开代码进行SQL注入攻击)使用你的编辑器的缩小特性使代码变小……我编辑了这个问题使它更清晰。如果你想提高别人对它的理解,你也可以考虑给你的控件有意义的ID。我认为OP意味着更短,即更简洁。你也可以使用K&R风格的括号而不是BSD。这样可以节省哟。u每个块都有一行。这应该扩展以回答原始问题:“UpdateMedicinerRecordQuantity”方法应该得到两个名为“tableName”和“columnName”的附加参数,使其在原始代码的所有四个位置都可重用。否则,我打赌OP会去复制/粘贴/修改你的例子四次以上。@Doc Brown,请随意编辑我的答案并包含此重构。谢谢你的帮助,下次我会记住控件的名称。我真的很担心。还有一件事,它是一个简单的窗口应用程序,所有操作都将在后台运行,那么它如何受到SQLInjection的攻击。@avirk:用户可以在其中一个文本框中输入精心编制的SQL命令,并在数据库中执行任何类型的操作(包括删除表)。请看这里以获得进一步的解释:那么我如何才能阻止我的应用程序使用它。@avirk,看看哪个应用程序使用参数化查询,这就是如何阻止它的。在这幅漫画中,他们称他为Bobby Tables,但是同一件事
if (!HasPriceValue() && !HasQuantityValue())
{
MessageBox.Show("No value entred for update.");
}
else
{
ConnectionClass.OpenConnection();
if (HasQuantityValue())
{
SqlCommand cmd = new SqlCommand("update medicinerecord set quantity='" + textBox2.Text + "' where productid='"+comboBox1.Text+"'", ConnectionClass.OpenConnection());
cmd.ExecuteNonQuery();
}
if (HasPriceValue())
{
SqlCommand cmd = new SqlCommand("update myrecord set price='" + textBox4.Text + "' where productid='" + comboBox1.Text + "'", ConnectionClass.OpenConnection());
cmd.ExecuteNonQuery();
}
ConnectionClass.CloseConnection();
}