SqlDataReader与DataSet

时间:2015-07-16 02:52:09

标签: c# asp.net-mvc-5 dataset sqldatareader

我试图在用户登录网站时获取用户信息,当我使用DataSet时成功,但如果我想使用SqlDataReader,则错误显示:{ {1}}。我有搜索为什么会这样,我发现一篇文章说

  

Invalid attempt to read when reader is closed要求连接保持打开才能获得   来自服务器的数据,而SqlDataReader不需要   连接仍然是开放的。

我的问题是:我想知道如何使用DataSet?因此,当我想从数据库中获取数据时,我不必依赖SqlDataReader

当我尝试使用DataSet更改读取数据函数的结构时,会出现问题,因此可以随时重复使用。

以下是代码:

DatabaseManager类:

SqlDataReader

网络管理员课程:

public SqlDataReader GetInformationDataReader(string procName, SqlParameter[] parameters)
        {
            SqlDataReader reader = null;
            using (SqlConnection conn = new SqlConnection(connectionString))
            {
                conn.Open();
                using (SqlCommand cmd = new SqlCommand(procName, conn))
                {
                    cmd.CommandType = CommandType.StoredProcedure;
                    if (parameters != null)
                    {
                        foreach(SqlParameter parameter in parameters)
                        {
                            cmd.Parameters.Add(parameter);
                        }
                    }
                    reader = cmd.ExecuteReader();
                }
            }
            return reader;
        }

控制器:

public ModelContexts.InformationContext GetInformation(string username)
        {
            SqlDataReader reader = null;
            ModelContexts.InformationContext context = new ModelContexts.InformationContext();
            SqlParameter[] parameters =
            {
                new SqlParameter("@Username", SqlDbType.NVarChar, 50)
            };
            parameters[0].Value = username;
            try
            {
                reader = DatabaseManager.Instance.GetInformationDataReader("GetInformation", parameters);
                while(reader.Read())
                {
                    context.FirstName = reader["FirstName"].ToString();
                    context.LastName = reader["LastName"].ToString();
                    context.Email = reader["Email"].ToString();
                }
            }
            catch(Exception ex)
            {
                throw new ArgumentException(ex.Message);
            }
            return context;
        }

Model包含带有getter和setter的字符串返回值(FirstName,LastName和Email)。

View包含html标签,并对Model中的FirstName,LastName和Email进行编码。

感谢您的回答。

感谢。

2 个答案:

答案 0 :(得分:2)

这是一种可用于保持代码非常干净的方法,允许您在连接仍处于打开状态时从SqlDataReader读取。它利用了传递代表的优势。希望代码是可以理解的。您可以调整它以满足您的特定需求,但希望它可以为您提供另一种选择。

public void GetInformationDataReader(string procName, SqlParameter[] parameters, Action<SqlDataReader> processRow)
{
    SqlDataReader reader = null;
    using (SqlConnection conn = new SqlConnection(connectionString))
    {
        conn.Open();
        using (SqlCommand cmd = new SqlCommand(procName, conn))
        {
            cmd.CommandType = CommandType.StoredProcedure;
            if (parameters != null)
            {
                foreach(SqlParameter parameter in parameters)
                {
                    cmd.Parameters.Add(parameter);
                }
            }
            using (SqlDataReader dataReader = cmd.ExecuteReader())
            {
                while (dataReader.Read())
                {
                    // call delegate here.
                    processRow(dataReader);
                }
            }
        }
    }
    return reader;
}

public ModelContexts.InformationContext GetInformation(string username)
{
    SqlDataReader reader = null;
    ModelContexts.InformationContext context = new ModelContexts.InformationContext();
    SqlParameter[] parameters =
    {
        new SqlParameter("@Username", SqlDbType.NVarChar, 50)
    };
    parameters[0].Value = username;
    try
    {
        // Instead of returning a reader, pass in a delegate that will perform the work
        // on the data reader at the right time, and while the connection is still open.
        DatabaseManager.Instance.GetInformationDataReader(
            "GetInformation",
            parameters,
            reader => {
                context.FirstName = reader["FirstName"].ToString();
                context.LastName = reader["LastName"].ToString();
                context.Email = reader["Email"].ToString();
            });
    }
    catch(Exception ex)
    {
        throw new ArgumentException(ex.Message);
    }
    return context;
}

简要说明:

您会注意到代码的整体结构与您已有的非常相似。唯一的变化是:

  • 而不是返回SqlDataReaderGetInformationDataReader()方法 接受 Action<SqlDataReader>代表。
  • GetInformationDataReader()方法中,在正确的时间调用委托,而连接仍处于打开状态。
  • 修改了对GetInformationDataReader()的调用,以作为代理传递代码块。

这种模式对于这些情况非常有用。它使代码可重用,它使它非常干净和分离,并且它不会阻止您从using构造中受益以避免资源/连接泄漏。

答案 1 :(得分:1)

您已将SqlConnection对象包装在using子句中,因此在其SqlConnect.Dispose结束时调用,关闭连接。无论呼叫者消费的是哪个SqlDataReader都不再具有开放式连接,因此您就会收到错误。

  

而DataSet不需要连接保持打开状态。

这不完全正确。 DataSet只是在SqlDataAdapter(该类的Fill()方法)调用时通常填充的对象。 SqlDataAdapter处理SqlConnection的开启和关闭,这很可能就是为什么评论会说明这一点。但它处理的是一个不同的类,而不是DataSet本身。可以将DataSet视为包含SqlCommand的结果集的对象。

回答您的评论......

  

那么,我不应该使用关键字来解决这个问题吗?在所有的Sql关键字中?

我也不会采取这种方法。你可以很容易地使用该模型获得连接泄漏错误,并且用尽排除连接可能是一个不太有趣的问题。

通常最好使用您的数据,然后关闭/处置您的连接。有一种说法,&#34;开放晚,早关闭&#34;。 通常您希望如何处理此问题。对于您正在处理的这个问题,我不会尝试在类方法之间传递SqlDataReader对象。解决方法(保持连接打开)非常容易出错。

另一个过程,回到我们提到的事情,不要使用SqlDataReader。循环读取每一行没有任何好处。根据您的结果集,只需填写DataSet(或通常更合适,DataTable),然后返回Data[Set | Table],或者更好地返回更能代表数据的对象它属于。