简体   繁体   English

使SqlDataReader在n层上保持打开状态

[英]Keeping the SqlDataReader open across an n-tiered layer

I have a Database class that abstracts the ExecuteNonQuery() and ExecuteReader() of SqlCommand. 我有一个Database类,它抽象了SqlCommand的ExecuteNonQuery()和ExecuteReader()。 Due to wrapping the Sqlconnection and SqlCommand around using blocks, the SqlDataReader gets closed after the CustomExecuteReader() is called, therefore I can't read the SqlReaderResultSet at the business level layer. 由于使用块来包装Sqlconnection和SqlCommand,因此在调用CustomExecuteReader()之后SqlDataReader会关闭,因此我无法在业务层读取SqlReaderResultSet。 Code below. 下面的代码。 Thanks guys for the feedback. 谢谢大家的反馈。

public static SqlDataReader SqlReaderResultSet { get; set; }    

public static SqlDataReader CustomExecuteReader(string storedProc)
    {
        using (var conn = new SqlConnection(ConnectionString))
        {
            var cmd = new SqlCommand(storedProc, conn) {CommandType = CommandType.StoredProcedure};                

            try
            {
                conn.Open();
                SqlReaderResultSet = cmd.ExecuteReader();
            }
            catch (InvalidOperationException)
            {
                if (conn.State.Equals(ConnectionState.Closed))
                    conn.Open();
            }
            finally
            {                    
                conn.Close();
            }

        }
        return SqlReaderResultSet;
    }

"I can't read the SqlReaderResultSet at the business level layer" - and you shouldn't. “我无法在业务层读取SqlReaderResultSet”-您不应这样做。 Data should be passed using data transfer objects, never through a low level data access structure. 数据应使用数据传输对象传递,而不应通过低级数据访问结构传递。

I recommend changing your approach so that the method you describe above iterates the records in the datareader, and creates a list of objects. 我建议更改您的方法,以使您上面描述的方法可以迭代数据读取器中的记录,并创建对象列表。 That list of objects is what should be returned and worked on. 该对象列表就是应该返回并处理的对象。

Iterator Blocks can be a way around this. 迭代器块可以解决此问题。 It is legal and generally safe to do the following: 进行以下操作是合法且总体上安全的:

IEnumerable<MyFancyData> ResultSet {
    get {
        using(DbConnection conn = ...) 
        using(DbCommand cmd = ...) {
            conn.Open();

            using(DbDataReader reader = cmd.ExecuteReader()) {
                while(reader.Read()) {
                    yield return new MyFancyData(reader[0], reader[42] ...);
                }
            }
        }
    }
}

Each time you enumerate the ResultSet property, the connection will be constructed again - and Disposed of afterwards (foreach and other IEnumerator<> consumers will appropriately call the Dispose() method of the generator, allowing the using block to do its thing). 每次枚举ResultSet属性时,都会重新构造连接-然后进行Dispose() foreach和其他IEnumerator<>使用者将适当地调用生成器的Dispose()方法,从而允许using块执行其操作)。

This approach retains the lazy as-you-need it evaluation of the items from the data reader (which can be relevant when your data set becomes large), which still cleaning abstracting away sql-level details from the public API. 这种方法保留了对数据读取器中项目的懒惰按需评估(当您的数据集变大时这可能是相关的),这仍然清除了从公共API提取sql级详细信息的情况。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM