卡在 SqlDataReader.GetValues 方法上

Posted

技术标签:

【中文标题】卡在 SqlDataReader.GetValues 方法上【英文标题】:Stuck on SqlDataReader.GetValues Method 【发布时间】:2014-02-06 19:19:22 【问题描述】:

我正在调用一个 SQL 存储过程,该过程返回一个用户及其老板的小表。我想做的是将此信息与我的应用程序不同部分中的变量进行比较,以启用/禁用 GridView 行的编辑。为此,GetValues 方法似乎会返回我需要的内容,即存储过程返回的整个数据集。我的想法是,一旦我的应用程序中有这些数据,我可以将该数据集加载到一个数组中,然后循环通过它来做我需要做的事情。

问题是这样的。在下面的代码中,我收到了错误

无法将类型“int”隐式转换为“object”

当我查看此方法上的documentation 时,返回值为int

我的问题是,既然存储过程包含字符串数据(用户名和老板名),为什么GetValues mehtod 返回int?我的实际数据如何表示为数字以及如何将我的数据放入基于字符串的数组中?

我一直在互联网上查看许多示例和信息,这似乎是新人遇到的常见问题。我只是不理解或得到它,而且我没有取得任何进展。非常感谢任何帮助!

    public Object[] GetDeptAppData()
    
        Object[] myObject;
        string sp_deptapp, sp_status, sp_supervisor;

        //execute stored procedure to get data from database
        SqlConnection sqlConnection = new SqlConnection("Data Source=MyServer;Initial Catalog=MyCatalog;Persist Security Info=True;User ID=MyUser;Password=MyPassword");
        SqlCommand cmd = new SqlCommand();
        SqlDataReader reader;

        cmd.CommandText = "SP_Admin_DeptApp_Load";
        cmd.CommandType = CommandType.StoredProcedure;

        cmd.Connection = sqlConnection;
        sqlConnection.Open();
        reader = cmd.ExecuteReader();

        if (reader.HasRows == true)
        
            //sp_deptapp = reader.GetValue(0).ToString();
            //sp_status = reader.GetValue(1).ToString();
            //sp_supervisor = reader.GetValue(2).ToString();

            myObject = reader.GetValues(myObject);
        
        else
        
            //nothing in reader, throw exception
        
        sqlConnection.Close();

        return myObject;
    

【问题讨论】:

【参考方案1】:

你遇到的错误位于这一行:

myObject = reader.GetValues(myObject);

myObject 是一个对象数组,GetValues 方法返回一个整数,其中包含放置在数组中的计数。因此,为了解决您的错误,您可以将行更改为以下内容:

var count = reader.GetValues(myObject);

另外,在您的代码中,您只检索一行数据。如果您只期望一排,这当然可以。当期望多行时,您通常会像这样遍历这些行:

while (reader.Read())

    // Read row and add row to list

有关如何使用 SqlDataReader 的示例,请参阅此link。


示例

如果要检索多行并存储数据,我建议添加一个类来存储一行的数据(您可能需要验证数据类型,以便它们与 SP 返回的类型匹配):

public class Data

    public string DeptApp  get; set; 
    public string Status  get; set;  // this might be another data type
    public string Supervisor  get; set; 

然后按如下方式检索行:

public Data[] GetDeptAppData()

    //execute stored procedure to get data from database
    using (SqlConnection sqlConnection = new SqlConnection("Data Source=MyServer;Initial Catalog=MyCatalog;Persist Security Info=True;User ID=MyUser;Password=MyPassword"))
    
        SqlCommand cmd = new SqlCommand();
        cmd.CommandText = "SP_Admin_DeptApp_Load";
        cmd.CommandType = CommandType.StoredProcedure;
        cmd.Connection = sqlConnection;
        sqlConnection.Open();
        using (var reader = cmd.ExecuteReader())
        
            if (!reader.HasRows)
            
                // throw exception
            
            var lst = new List<Data>();
            while (reader.Read())
            
                var row = new Data();
                row.DeptApp = reader.GetString(0);
                row.Status = reader.GetString(1);
                row.Supervisor = reader.GetString(2);
                lst.Add(row);
            
            return lst.ToArray();
        
    

【讨论】:

"myObject 是一个对象数组" - 可以吗?我在想 myObject 将是一个包含存储过程结果的单个对象。 “GetValues 方法返回一个整数,其中包含放置在数组中的计数。” - 所以它所做的只是计算一些东西?它算什么,我为什么要关心?我并不关心从存储过程返回的数据有多少行,我关心的是实际数据。看起来var COUNT 将只包含一个数字,表示存储过程中有多少项目。 @Rob: 不,myObject 被声明为Object[],所以它是一个对象数组。 SqlDataReader 用于检索一行又一行的数据。 GetValues 将数据存储在参数中并返回从当前行读取的字段数 (!)。如果要检索多行,则需要添加一个循环。我会扩展我的答案。 我之前有 WHILE lopp,但我认为我不需要它,因为我希望 GetValues() 将我的所有数据一次性返回给 myObject @Rob:我已经更新了示例。请注意,SqlDataReader 是一种以只进方式快速检索数据的方法。它确实逐行返回数据。 @Rob 如果您想在一个命令中执行所有操作,您可能需要查看SqlDataAdapterFill( 命令。它会在一个步骤中为您提供所有结果并将结果存储在DataTableDataSet 对象中。【参考方案2】:

GetValues 返回一个int,即“数组中Object 的实例数。”,因此您不能将其分配给myObject。这是神秘的。它实际上意味着(我相信)为当前行返回的列值的数量。

你需要:

int numColumnsRetrieved = reader.GetValues(myObject);

或类似的东西。

然后,您的数据将显示在 myObject 中,但仅针对当前行,根据文档“使用当前行的列值填充对象数组”。所以,还是需要迭代,比如:

var myObjectList = new List<object[]>(); // ... shudder ...
while (reader.Read())

    var myObject[] = new object[reader.FieldCount];
    int instances = reader.GetValues(myObject);
    myObjectList.Add(myObject);

您可能会发现使用更具体的方法很有用,例如GetString

var usersAndBosses = new List<Tuple<string, string>>();
while (reader.Read())

    string username = reader.GetString(0); // column index 0
    string bossname = reader.GetString(1); // column index 1
    usersAndBosses.Add(Tuple.Create(username, bossname));

编辑

如果您想对来自GetValues 的返回值进行虚假使用,您可以将字符串表展平为字符串列表:

var myStringList = new List<string>();
while (reader.Read())

    var myObject[] = new object[100];
    int colCount = reader.GetValues(myObject);
    for (int i = 0; i < colCount; i++)
    
        myStringList.Add((string)myObject[i]);
    

【讨论】:

与我对另一个回答的人的问题相同,为什么我关心“计算数组中对象的实例”?我关心的是数据,而不是有多少。一个数字对我没有任何作用。我喜欢你的第二个块,我在上面的代码中有类似的东西被注释掉了。我可以使用 while(reader.read()) 识别 3 个唯一的数据列,使用 reader.getValue(0).ToString(),但是我只需要将它加载到数组中,然后传递出去使用 RETURN 的方法。 第一个答案:我会避免传递对象数组,C# 是一种强类型语言(即使元组也是惰性编码,尽管至少您可以在编译时强制执行类型检查)。跨度> 第二个答案:例如,如果您传入一个长度为 10 的对象数组,如果只有 3 列,它会告诉您它只将 3 个值放入长度为 10 的数组中。我没有从来没有发现它的用途。 GetValues 并非设计为转储所有行和列,没有方法,因此您需要使用 reader.Read() 进行迭代【参考方案3】:

下面是 ExecuteSelectQuery(...) 函数来获取任何 SELECT 查询的结果。

ExecuteSelectQuery 的结果是 System.Object 元素的数组列表,可以在调用代码中转换为所需的类型。

public sealed class DbPerformer

    private const string mysqlServerName = "localhost";
    private const string dataBaseName = "testdb";
    private const string uid = "login";
    private const string password = "password";

    private MySqlConnection connection;

    public DbPerformer()
    
        string connectionString;
        connectionString = "server=" + mySqlServerName + ";";
        connectionString += "Username=" + uid + ";";
        connectionString += "Password=" + password;

        connection = new MySqlConnection(connectionString);
    

    private bool OpenConnection()
    
        try
        
            connection.Open();
            return true;
        
        catch (MySqlException ex)
        
            switch (ex.Number)
            
                case 0:
                    Debug.WriteLine("Cannot connect to server 0", mySqlServerName);
                    break;

                case 1045:
                    Debug.WriteLine("Invalid username/password.");
                    break;
            
            return false;
        
    

    private bool CloseConnection()
    
        try
        
            connection.Close();
            return true;
        
        catch (MySqlException ex)
        
            Debug.WriteLine(ex.Message);
            return true;
        
    

    public List<object[]> ExecuteSelectQuery(string selectQuery)
    
        List<object[]> resultList = new List<object[]>();

        if (true == this.OpenConnection())
        
            MySqlCommand command = new MySqlCommand(selectQuery, connection);
            MySqlDataReader resultReader = command.ExecuteReader();

            while (resultReader.Read())
            
                object[] resultRow = new object[resultReader.FieldCount];
                resultReader.GetValues(resultRow);
                resultList.Add(resultRow);
            

            resultReader.Close();
            this.CloseConnection();
        
        else
        
            throw new Exception("Can not open connection to database.");
        
        return resultList;
    

【讨论】:

以上是关于卡在 SqlDataReader.GetValues 方法上的主要内容,如果未能解决你的问题,请参考以下文章

电脑开机卡在lenovo界面,无法进入bios

克隆卡在检查源

用mis文件重新安装MYSQL卡在最后一步,卡在Starting Server,删除注册表无效的解决方案

MPMoviePlayer 卡在“正在加载...”

HP P420阵列卡在initializing

Vue.js 卡在 40% 的服务如何恢复?