[英]foreach (variable in checklistbox.checkedItems) in c# vs2012
I'm trying to make a program where the user can select several items in a combo listbox, retrieves its id from my SQL database, returns the id, and inserts the id in another table. 我正在尝试制作一个程序,用户可以在其中选择组合列表框中的多个项,从我的SQL数据库中检索其ID,返回该ID,然后将该ID插入另一个表中。 I'm not sure if this is the most effective way, and suggestions are welcome.
我不确定这是否是最有效的方法,欢迎提出建议。 However, I ran into the problem in how to complete my foreach statement.
但是,我遇到了如何完成我的foreach语句的问题。 What should I place in the position marked by X below?
我应该在下面的X标记的位置放置什么? (in the
foreach
statement) (在
foreach
语句中)
Here's my code: ( clbGeneral
is the name of the checklistbox) 这是我的代码:(
clbGeneral
是清单clbGeneral
的名称)
if (clbGeneral.CheckedIndices.Count != 0)
{
foreach ( X in clbGeneral.CheckedItems)
{
con.Open();
cmd = new SqlCommand("SELECT serv_id from services where serv_name='" + clbGeneral.SelectedItem.ToString() + "';", con);
serv_id = (int)cmd.ExecuteScalar();
con.Close();
transactSQL();
MessageBox.Show(clbGeneral.SelectedItem.ToString());
}
}
the transactSQL function: transactSQL函数:
public void transactSQL() {
con.Open();
cmd = new SqlCommand("INSERT INTO transactions VALUES ('" + txtDate.Text + "','" + dataPnts.SelectedRows[0].Cells[3].Value.ToString() + "','" + dataProvs.SelectedRows[0].Cells[4].Value.ToString() + "','" +serv_id.ToString() + "');", con);
cmd.ExecuteNonQuery();
con.Close();
}
CheckedListBox.Items
is a collection of Objects
and CheckedListBox.CheckedItems
returns the subset of objects
in CheckedListBox Items
only those items whose System.Windows.Forms.CheckState
is Checked
or Indeterminate
. CheckedListBox.Items
是Objects
的集合, CheckedListBox.CheckedItems
返回System.Windows.Forms.CheckState
为Checked
或Indeterminate
那些项目,才返回CheckedListBox Items
的objects
子集。
You can use Type var
or object
to represent each item in the CheckedItems and call ToString()
to get the each checked Item in the foreach
loop. 您可以使用Type
var
或object
表示CheckedItems中的每个项目,并调用ToString()
以获取foreach
循环中的每个选中的项目。
Try This: 尝试这个:
foreach (var item in clbGeneral.CheckedItems)
{
con.Open();
cmd = new SqlCommand("SELECT serv_id from services where serv_name='" + item
.ToString() + "';", con);
serv_id = (int)cmd.ExecuteScalar();
con.Close();
transactSQL();
MessageBox.Show(item.ToString());
}
foreach (var checkedItem in clbGeneral.CheckedItems)
{
}
You don't actually have that much choice there. 您实际上在那里没有太多选择。
CheckedListBox.CheckedItems
is a CheckedItemCollection
which happens to store its elements as plain object
s. CheckedListBox.CheckedItems
是CheckedItemCollection
这恰好存储其元素为纯object
秒。 So the foreach will only be able to get individual items of type object
from that: 因此,foreach只能从中获取
object
类型的单个项:
foreach (object item in clbGeneral.CheckedItems)
{ … }
Of course, you could also use var item
, letting the compiler infer the type automatically. 当然,您也可以使用
var item
,让编译器自动推断类型。 That won't change the variable type though, as the compiler would perform the same thinking process as I did above. 不过,这不会改变变量类型,因为编译器将执行与我上面相同的思维过程。 So
item
would still be an object
. 因此
item
仍然是一个object
。
Of what type those objects actually are, depends on what items you put into it in the first place. 什么类型的这些对象实际上是取决于你是什么项目投入它摆在首位。 If all those items are of a certain type, you can type-cast them inside the loop.
如果所有这些项目都属于某种类型,则可以在循环内进行类型转换。
To continue further though, your SQL statement within the loop should reflect the item of that loop iteration, and not just the selected item. 但是,要继续进行下去,循环中的SQL语句应反映该循环迭代的项目,而不仅是所选的项目。 So your command could look like this—but that again depends a bit on what objects you added to the list, and if their
ToString
value is good enough for the query: 因此,您的命令可能看起来像这样,但这又取决于您向列表中添加了哪些对象,以及它们的
ToString
值对于查询是否足够好:
cmd = new SqlCommand("SELECT serv_id from services where serv_name='" + item.ToString() + "';", con);
So that was the first part of my answer. 这就是我回答的第一部分。 The next part is more of a code review, to make sure you don't do bad stuff.
下一部分是更多的代码审查,以确保您没有做不好的事情。 First of all, for SqlConnections , the recommended way to close it is by not doing it yourself, but using the connection within a
using
statement. 首先,对于SqlConnections ,关闭它的推荐方法是不自己做,而是在
using
语句中使用连接。 That way you ensure that the connection is closed even if errors might terminate the current code: 这样,即使错误可能终止当前代码,您也可以确保关闭连接:
using (var con = OpenConnection())
{
con.Open();
var cmd = new SqlCommand(…, con);
cmd.ExecuteScalar();
}
Next, you really shouldn't just append some text into a SQL query. 接下来,您实际上不应该只是将一些文本附加到SQL查询中。 The chance for SQL injections is just to high.
SQL注入的机会很高。 Instead, you should just use parameterized queries, which automatically take care of passing the values properly, escaping stuff as needed etc.:
相反,您应该只使用参数化查询,该查询将自动处理正确传递值,根据需要转义内容的工作,等等:
var cmd = new SqlCommand("SELECT serv_id from services where serv_name=@Name", con);
cmd.Parameters.Add("@Name", SqlDbType.VarChar).Value = item.ToString();
cmd.ExecuteScalar();
What should I place in the position marked by X below?
我应该在下面的X标记的位置放置什么?
As noted in other answers, you can just use "var" and let the compiler worry about it. 如其他答案中所述,您可以只使用“ var”并让编译器担心它。
I'm not sure if this is the most effective way, and suggestions are welcome.
我不确定这是否是最有效的方法,欢迎提出建议。
1) If I were you, I wouldn't open and close the connection inside the foreach--I'd open it just before the loop and close it just after. 1)如果我是你,则不会在foreach内部打开和关闭连接-我会在循环之前将其打开,而在循环之后将其关闭。 And, actually, I'd wrap it in a try-finally with the close inside the finally.
而且,实际上,我将其包装在try-finally中,并在其内部将其收尾。 In order for this to work, you'll need to not open and close inside of
transactSQL
, either. 为了使其正常工作,您也无需打开和关闭
transactSQL
内部。 If that breaks other parts of your code, you could introduce a new variable that tracks whether con was open or closed when you entered the method and then refers to it to decide whether or not to call open and/or close. 如果这破坏了代码的其他部分,则可以引入一个新变量,该变量在输入方法时跟踪con是打开还是关闭,然后引用该变量来决定是否调用open和/或close。
2) Instead of making 2 round trips to the database, you can do it all in 1 call. 2)您无需在数据库中进行2次往返,而是可以在一次调用中完成所有操作。 This would actually eliminate the need to call transactSQL at all.
这实际上将根本不需要调用transactSQL。 I believe the following would work for you (or at least something very close to it):
我相信以下内容对您有用(或至少很接近):
if (clbGeneral.CheckedIndices.Count != 0)
{
con.Open();
try
{
foreach (var item in clbGeneral.CheckedItems)
{
string sql=string.Format("INSERT INTO transactions (<column names here>) " +
"SELECT '{0}', '{1}', '{2}', serv_id "+ // add "TOP 1" if you might get more than 1 result and only want to do 1 insert
"FROM services " +
"WHERE serv_name=@Name); ",
txtDate.Text, dataPnts.SelectedRows[0].Cells[3].Value.ToString(),
dataProvs.SelectedRows[0].Cells[4].Value.ToString(), item.ToString());
cmd = new SqlCommand(sql, con);
cmd.Parameters.Add("@Name", SqlDbType.VarChar).Value = item.ToString();
cmd.ExecuteNonQuery();
MessageBox.Show(clbGeneral.SelectedItem.ToString());
}
}
finally
{
con.Close();
}
}
The first time I run an ad hoc query, I like to put a debugging break point just after I've set sql
and before I actually use it. 第一次运行临时查询时,我想在设置
sql
和实际使用它之前放置一个调试断点。 That way I can grab the value of the SQL that was generated and then copy-paste it into Enterprise Manager and make sure it looks correct and doesn't generate and compile time errors before executing. 这样,我可以获取所生成的SQL的值,然后将其复制粘贴到企业管理器中,并确保它看起来正确并且在执行之前不会生成和编译时间错误。 I'd recommend you do that here since I can't check against your DB to make sure my syntax is 100% correct :)
我建议您在这里这样做,因为我无法检查您的数据库以确保我的语法是100%正确的:)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.