问题 在另一个方法的formload事件中调用一个方法

安德鲁·马努亚

知名会员
已加入
五月30,2019
留言内容
75
编程经验
Beginner
大家好,
我正在开发一个管理库存的应用程序。
我正在将与毒品订单相关的数据加载到窗口形式(基本上到dataGridView中),并且需要计算列的总和。出于上述目的,我在FormLoad事件中使用以下代码;

int d = 0;
for(int n=0; n<dataGridViewOrder .Rows.Count; n ++)
{
d + = Convert.ToInt32(dataGridViewOrder.Rows [n] .Cells [5] .Value);
}

我想根据变量的值在同一个类中的不同方法中执行条件"d" defined above.

但是,我不确定如何完成此任务。此外,我可以创建上面的计算值"d"作为同一类中的一个单独函数,因此不确定如何在另一个传递参数值以评估条件的函数中调用它。

有人可以帮我解决这个问题吗?

先感谢您。

亲切的问候,

安德鲁
 

安德鲁·马努亚

知名会员
已加入
五月30,2019
留言内容
75
编程经验
Beginner
大家好,

请忽略我以前的帖子。我的实际要求如下。

我的要求是,我在数据库表中有一个列,名为"issuequantity"。我的目的是计算"issuequantity" for a given "orderID".
数据库列是orderID,drugID,drugName和issueQuantity。
我在窗口窗体中创建了一个文本框(名为textbox1),并尝试使用下面的代码来计算问题数量的总和,但是没有按预期工作。

SqlConnection con =新的SqlConnection(@"数据源= ABC \ SQLEXPRESS;初始目录= Order_DB;集成安全性=真");
con.Open();
字符串sqlSelectQuery ="从tbl_drug的WHERE orderID = 1中选择SELECT SUM(issuequantity)";
SqlCommand cmd =新的SqlCommand(sqlSelectQuery,con);
SqlDataReader dr = cmd.ExecuteReader();
textBox1.Text = (dr["SUM(issuequantity)"].ToString ());

con.Close();

有人可以帮我解决上面的代码,或者向我提出解决方案来计算总和"issuequantity"列可能使用动态数组?

先感谢您。

亲切的问候,

安德鲁
 

金西尼

C#论坛主持人
工作人员
已加入
2011年4月23日
留言内容
3,535
地点
悉尼,澳大利亚
编程经验
10+
The reason the code you posted is not working is that you never call Read on your data reader. ExecuteReader executes the query but you have to call Read to load the result set, once for each row.

That said, you shouldn't be using a data reader anyway. You are only retrieving a single value and the ExecuteScalar method exists for that specifically.
 

羊皮

退休程序员
工作人员
已加入
2018年9月5日
留言内容
1,933
地点
英国
编程经验
10+
我第二次使用 ExecuteScaler 使用块-请参见链接。如果您只检索一条记录,则不需要阅读器。如果您要说的话,读者就足够了。从包含数据的行选择中读取多个字段,您需要在其中逐一筛选并检查给定条件。与使用缩放器相比,阅读器在资源方面要重得多。您还应该使用using块来封装代码,因为它们会自动释放其中使用和使用的任何资源。请参阅上面的链接上的示例代码,如下所示:::

C#:
static public int AddProductCategory(string newName, string connString)
{
    Int32 newProdID = 0;
    string sql =
        "INSERT INTO Production.ProductCategory (Name) VALUES (@Name); "
        + "SELECT CAST(scope_identity() AS int)";
    using (SqlConnection conn = new SqlConnection(connString))
    {
        SqlCommand cmd = new SqlCommand(sql, conn);
        cmd.Parameters.Add("@Name", SqlDbType.VarChar);
        cmd.Parameters["@name"].Value = newName;
        try
        {
            conn.Open();
            newProdID = (Int32)cmd.ExecuteScalar();
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
    }
    return (int)newProdID;
}

希望您觉得这有用。
 

金西尼

C#论坛主持人
工作人员
已加入
2011年4月23日
留言内容
3,535
地点
悉尼,澳大利亚
编程经验
10+
与使用缩放器相比,阅读器在资源方面要重得多。
That's not actually true. Calling ExecuteScalar just makes for simpler code, but it actually uses a data reader internally, just as the Fill method of a data adapter does. Here's the implementation of OleDbCommand.ExecuteScalar:
C#:
public override object ExecuteScalar()
{
  OleDbConnection.ExecutePermission.Demand();
  IntPtr hScp;
  Bid.ScopeEnter(out hScp, "<oledb.OleDbCommand.ExecuteScalar|API> %d#\n", this.ObjectID);
  try
  {
    object obj = (object) null;
    this._executeQuery = true;
    using (OleDbDataReader oleDbDataReader = this.ExecuteReaderInternal(CommandBehavior.Default, nameof (ExecuteScalar)))
    {
      if (oleDbDataReader.Read())
      {
        if (0 < oleDbDataReader.FieldCount)
          obj = oleDbDataReader.GetValue(0);
      }
    }
    return obj;
  }
  finally
  {
    Bid.ScopeLeave(ref hScp);
  }
}
 

羊皮

退休程序员
工作人员
已加入
2018年9月5日
留言内容
1,933
地点
英国
编程经验
10+
知道这很有趣,但是您正在谈论ExecuteScalar方法的内部结构。这种类型的内部结构是没有意义的。您能指出我来自Microsoft文档的消息来源,该消息证实了您写的John吗?在我看来;我一直认为这是不使用递归方法(包括读者)的任何实现而返回第一个结果的一种有趣的方法。毕竟,这就是ExecuteScalar只返回一个结果的原因。

安德鲁,我看到ExecuteNonQuery,ExecuteScalar和ExecuteReader解释的最好方法是在此 SO主题 从2012年开始。为方便起见,我将帖子发布到了论坛中::
ExecuteNonQuery():

  1. 仅适用于操作查询(创建,更改,删除,插入,更新,删除)。
  2. 返回由查询影响的行数。
  3. 返回类型为int
  4. 返回值是可选的,可以分配给整数变量。
ExecuteReader():

  1. 将与操作和非操作查询一起使用(选择)
  2. 返回查询选择的行的集合。
  3. 返回类型为DataReader。
  4. 返回值是强制性的,应将其分配给另一个对象DataReader。
ExecuteScalar():

  1. 将与包含聚合函数的非操作查询一起使用。
  2. 返回查询结果的第一行和第一列的值。
  3. 返回类型是对象。
  4. 返回值是强制性的,应将其分配给所需类型的变量。
此外,如果您想坚持使用阅读器,可以找到 关于它们的文档在这里,然后您就可以看到缺少的内容 这里的示例代码。 - 搜索 // Call Read before accessing data.
 

安德鲁·马努亚

知名会员
已加入
五月30,2019
留言内容
75
编程经验
Beginner
大家好,
非常感谢您的宝贵意见。
我将按照上述说明运行程序,并相应地发布反馈。
实际上,我正在基于orderID检索多个数据值,并且一个orderID可以具有多个"issuequantity" values.
但是,我将继续给出示例。
再次非常感谢大家。
亲切的问候,
安德鲁
 

金西尼

C#论坛主持人
工作人员
已加入
2011年4月23日
留言内容
3,535
地点
悉尼,澳大利亚
编程经验
10+
知道这很有趣,但是您正在谈论ExecuteScalar方法的内部结构。
I am, and I'm doing so because that has a direct effect on the resources required. You said that ExecuteScalar is less resource-intensive than ExecuteReader but that is not true because they both do the same thing under the hood.
这种类型的内部结构是没有意义的。
It makes perfect sense. A data reader reads data. Calling ExecuteScalar requires that data be read so why would it not use the functionality built into a data reader to do that? If it didn't do so, it would just have to reproduce that functionality, thus violating the DRY principal.
您能指出我来自Microsoft文档的消息来源,该消息证实了您写的John吗?
There's nothing in the documentation because it's an implementation detail that developers don't need to concern themselves with. I only brought it up because it demonstrates why what you said about relative resource usage is incorrect. What I posted is actual source code from the OleDbCommand class. I believe that VS alone can do it too but I have ReSharper configured to allow me to navigate to Framework implementations of members in the same way as you can navigate in your own code using Ctrl +点击.
在我看来;我一直认为这是不使用递归方法(包括读者)的任何实现而返回第一个结果的一种有趣的方法。毕竟,这就是ExecuteScalar只返回一个结果的原因。
ExecuteScalar exists because retrieving a single value from a database is a common operation and thus it saves the effort of repeatedly writing the same code involving a data reader. It uses a data reader internally because a data reader already implements the functionality to read data from a database. Reading a single value is still reading data. There's no reason that the lower-level mechanism to read data should be different based on whether you want a single value or multiple. There's a reason that beginners tend to use a data reader to read a single value when they don't know that ExecuteScalar exists.
 

羊皮

退休程序员
工作人员
已加入
2018年9月5日
留言内容
1,933
地点
英国
编程经验
10+
我似乎找不到我读过的文章,该文章解释了标量和读者使用不同的内部结构,同一篇文章在两者之间的执行时间也不同,这使阅读更加可信。到家时,我将尝试在Wayback Machine上进行挖掘。

在我读过这篇文章之前,我还相信两者的运作方式始终不同。因此,很高兴接受纠正。我们的错误使我们变得更好,知识更多。我想你不能相信阅读的所有内容。
 

跳伞

工作人员
已加入
2019年4月6日
留言内容
2,546
地点
弗吉尼亚州切萨皮克
编程经验
10+
Actually the efficiency is dependent on the database provider. It's up to each provider to override ExecuteScalar() to make it as efficient (or inefficient) as they please. From what I can see, they both effectively call the reader.00

OLEDB提供程序旨在成为通用驱动程序,因此在行为方面,它所做的事情最少令人惊讶。可以找到它的代码 这里.
C#:
        override public object ExecuteScalar() {
            OleDbConnection.ExecutePermission.Demand();
 
            IntPtr hscp;
            Bid.ScopeEnter(out hscp, "<oledb.OleDbCommand.ExecuteScalar|API> %d#\n", ObjectID);
            try {
                object value = null;
                _executeQuery = true;
                using(OleDbDataReader reader = ExecuteReaderInternal(CommandBehavior.Default, ADP.ExecuteScalar)) {
                    if (reader.Read() && (0 < reader.FieldCount)) {
                        value = reader.GetValue(0);
                    }
                }
                return value;
            }
            finally {
                Bid.ScopeLeave(ref hscp);
            }
        }

另一方面,可以找到的SQL实现 这里.
C#:
override public object ExecuteScalar() {
            SqlConnection.ExecutePermission.Demand();
 
            // Reset _pendingCancel upon entry into any Execute - used to synchronize state
            // between entry into Execute* API and the thread obtaining the stateObject.
            _pendingCancel = false;
 
            SqlStatistics statistics = null;
            IntPtr hscp;
            Bid.ScopeEnter(out hscp, "<sc.SqlCommand.ExecuteScalar|API> %d#", ObjectID);
            Bid.CorrelationTrace("<sc.SqlCommand.ExecuteScalar|API|Correlation> ObjectID%d#, ActivityID %ls\n", ObjectID);
 
            bool success = false;
            int? sqlExceptionNumber = null;
            try {
                statistics = SqlStatistics.StartTimer(Statistics);
                WriteBeginExecuteEvent();
                SqlDataReader ds;
                ds = RunExecuteReader(0, RunBehavior.ReturnImmediately, true, ADP.ExecuteScalar);
                object result = CompleteExecuteScalar(ds, false);
                success = true;
                return result;
            }
            catch (SqlException ex) {
                sqlExceptionNumber = ex.Number;
                throw;
            }
            finally {
                SqlStatistics.StopTimer(statistics);
                Bid.ScopeLeave(ref hscp);
                WriteEndExecuteEvent(success, sqlExceptionNumber, synchronous: true);
            }
        }

private object CompleteExecuteScalar(SqlDataReader ds, bool returnSqlValue) {
            object retResult = null;
 
            try {
                if (ds.Read()) {
                    if (ds.FieldCount > 0) {
                        if (returnSqlValue) {
                            retResult = ds.GetSqlValue(0);
                        }
                        else {
                            retResult = ds.GetValue(0);
                        }
                    }
                }
            }
            finally {
                // clean off the wire
                ds.Close();
            }
 
            return retResult;
        }
 

金西尼

C#论坛主持人
工作人员
已加入
2011年4月23日
留言内容
3,535
地点
悉尼,澳大利亚
编程经验
10+
@跳伞, 有道理。我专门指的是OleDb提供程序,而Sheepings可能一直在考虑SqlClient提供程序,因为它是为一个特定的数据源编写的,所以效率更高。
 

安德鲁·马努亚

知名会员
已加入
五月30,2019
留言内容
75
编程经验
Beginner
大家好,

感谢您的宝贵意见。但是,要想解决我面临的问题仍然有些困难。

我创建了一个公共方法来从数据库表中检索数据到dataGridView并评估条件。

请找到各自的;
C#:
SqlConnection con =新的SqlConnection(@"数据源= ABC \ SQLEXPRESS;初始目录= Order_DB;集成安全性=真");

public void LoadSumIssueQty()
        {
            con.Open();
            SqlDataAdapter sda = new SqlDataAdapter(@"SELECT orderID, drugID, issuequantity FROM tbl_drug WHERE orderID=1 ", con);
            DataTable dt = new DataTable();
            sda.Fill(dt);
            dataGridViewOrder.Rows.Clear();

            foreach (DataRow item in dt.Rows)
            {
                int n = dataGridViewOrder.Rows.Add();
                dataGridViewOrder.Rows[n].Cells[0].Value = item["orderID"].ToString();
                dataGridViewOrder.Rows[n].Cells[1].Value = item["drugID"].ToString();
                dataGridViewOrder.Rows[n].Cells[2].Value = item["issuequantity"].ToString();
            }

            int sumissuequantity = 0;
            for (int n = 0; n < dataGridViewOrder.Rows.Count; n++)
            {
                sumissuequantity += Convert.ToInt32(dataGridViewOrder.Rows[n].Cells[2].Value);
            }

            bool hasissue = false;
            if (sumissuequantity != 0)
            {
                hasissue = true;
            }
            else
            {
                hasissue = false;
            }           
            con.Close();
        }
创建上述方法后,我在窗体加载方法中调用了该方法,并且需要根据该方法的值在同一dataGridView上显示一个新列。"hasissue".

请在下面找到相应的代码;

C#:
private void Form1_Load(object sender, EventArgs e)
{
    LoadSumIssueQty();
      
    if (hasissue==true)
    {
        dataGridViewOrder.Columns[3].Visible = true;
    }
    else
    {
        dataGridViewOrder.Columns[3].Visible = false;
    }
}

笔记
基本上我在这里做的是,我正在检查是否针对特定药品签发了药品"orderID"如果是这样,请打开名为"Subsequent Issue"如果没有,请不要打开新列,"Subsequent Issue".
方法"LoadSumIssueQty"工作正常并产生预期结果。但是,在表单加载事件中运行if条件时遇到问题。
错误消息是," 名称“ hasissue”在当前上下文中不存在".

我可能在犯一个愚蠢的错误。但是,非常感谢您提供宝贵的反馈意见以纠正上述问题。

提前非常感谢您。

亲切的问候,

安德鲁
 
由主持人最后编辑:

跳伞

工作人员
已加入
2019年4月6日
留言内容
2,546
地点
弗吉尼亚州切萨皮克
编程经验
10+
That is because hasissue was declared as a local variable in your LoadSumIssueQty() method. Read up on scoping rules used by C#.

我建议您让方法返回一个布尔值标志(如果这是您真正需要的)。

As an aside, you can configure the DataGridView to do the column lookups and type conversions for you so that all you need to do is set the DataTable as the grid's DataSource property value. You can get rid of you loop over the table rows to populate the grid rows.

另外,您可以让SQL查询为您汇总该列。最好从实际的数据源/模型中获取数据,而不要询问您的视图。 (您似乎正在将所有数据加载到数据网格视图中,然后从视图中对该列求和。)
 

安德鲁·马努亚

知名会员
已加入
五月30,2019
留言内容
75
编程经验
Beginner
That is because hasissue was declared as a local variable in your LoadSumIssueQty() method. Read up on scoping rules used by C#.

我建议您让方法返回一个布尔值标志(如果这是您真正需要的)。

As an aside, you can configure the DataGridView to do the column lookups and type conversions for you so that all you need to do is set the DataTable as the grid's DataSource property value. You can get rid of you loop over the table rows to populate the grid rows.

另外,您可以让SQL查询为您汇总该列。最好从实际的数据源/模型中获取数据,而不要询问您的视图。 (您似乎正在将所有数据加载到数据网格视图中,然后从视图中对该列求和。)

你好,

非常感谢。

按照规定,我声明了"hasissue"作为公共变量,并且能够通过第二种方法访问它。现在,我可以继续我的工作了。

我将尝试使用dataGridView查找功能,因为它似乎也很方便。

我实际上是将加载的数据用于后续过程。

非常感谢你。

亲切的问候,

安德鲁
 
最佳 底部