SQLDataReader上的转换错误

时间:2010-05-20 07:20:52

标签: enterprise-library sqldatareader daab .net

我的网站正在使用企业库v 5.0。主要是DAAB。一些函数,如executioncalar,executionataset正在按预期工作。当我开始使用读者时出现问题

我在include类中有这个功能:

Public Function AssignedDepartmentDetail(ByVal Did As Integer) As SqlDataReader
    Dim reader As SqlDataReader
    Dim Command As SqlCommand = db.GetSqlStringCommand("select seomthing from somewhere where something = @did")
    db.AddInParameter(Command, "@did", Data.DbType.Int32, Did)
    reader = db.ExecuteReader(Command)
    reader.Read()
    Return reader
End Function

这是从我的aspx.vb调用的,如下所示:

reader = includes.AssignedDepartmentDetail(Did)
If reader.HasRows Then
    TheModule = reader("templatefilename")
    PageID = reader("id")
Else
    TheModule = "#"
End If

这会在db.ExecuteReader行上出现以下错误:

无法将“Microsoft.Practices.EnterpriseLibrary.Data.RefCountingDataReader”类型的对象强制转换为“System.Data.SqlClient.SqlDataReader”。

任何人都可以了解我如何开展这项工作。通过entlib与读者打交道时,我是否会遇到问题?

6 个答案:

答案 0 :(得分:3)

我会小心这个实现。 Enterprise Library Codeplex站点上有一个线程解释了这个背景: http://entlib.codeplex.com/Thread/View.aspx?ThreadId=212973

Chris Tavares解释说,返回.InnerReader是不好的,因为那时企业库的连接跟踪被抛弃(他的回复是从5月20日下午5:39): “这种方法将彻底搞砸你的连接管理。包装器的全部原因是我们可以执行额外的代码来清理处理时的东西。抓住内部读取器并抛弃外部将泄漏连接! “

所以是的,处理这个问题有点痛苦,我们处于相同的情况。

此致 麦克

答案 1 :(得分:1)

企业库中的ExecuteReader将IDataReader包装到RefCountingDataReader中,当SqlDataReader实现IDataReader接口时。

RefCountingDataReader具有可以强制转换为SqlDataReader的InnerReader属性。下面的示例是在C#中,但您可以轻松地将其转换为VB.NET。

SqlDataReader reader;
reader = ((RefCountingDataReader)db.ExecuteReader(command)).InnerReader as SqlDataReader;
if (reader != null)
    reader.Read();
return reader;

希望有所帮助

答案 2 :(得分:1)

我正在泄漏连接,因为我的所有DA方法都需要SqlDataReader。 现在我必须返回内部RefCountingDataReader并且永远不能关闭外部阅读器。 旧的Enterprise Library在返回SqlDataReader时工作正常。

答案 3 :(得分:1)

我已经考虑了ctavars在http://entlib.codeplex.com/discussions/212973http://entlib.codeplex.com/discussions/211288发布的评论和代码,从而产生了以下获取SQL数据读取器的通用方法。

通常,您在using语句中使用IDataReader,然后在可能时直接使用该引用。当您需要特定于SQL的内容时,请在其上调用AsSqlDataReader

在某处添加此扩展类:

/// <summary>
/// Obtains an <see cref="SqlDataReader"/> from less derived data readers in Enterprise Library
/// </summary>
/// <remarks>
/// See http://entlib.codeplex.com/discussions/212973 and http://entlib.codeplex.com/discussions/211288
/// for a discussion of why this is necessary
/// </remarks>
public static class SqlDataReaderExtension
{
    /// <summary>
    /// Allows the internal <see cref="SqlDataReader"/> of a <see cref="RefCountingDataReader"/> to be accessed safely
    /// </summary>
    /// <remarks>
    /// To ensure correct use, the returned reference must not be retained and used outside the scope of the input
    /// reference. This is so that the reference counting does not get broken. In practice this means calling this method
    /// on the base reader every time a reference to it is required.
    /// </remarks>
    public static SqlDataReader AsSqlDataReader(this RefCountingDataReader reader)
    {
        return (SqlDataReader)(reader.InnerReader);
    }

    /// <summary>
    /// Allows the internal <see cref="SqlDataReader"/> of a <see cref="IDataReader"/> to be accessed safely
    /// </summary>
    /// <remarks>
    /// To ensure correct use, the returned reference must not be retained and used outside the scope of the input
    /// reference. This is so that the reference counting does not get broken. In practice this means calling this method
    /// on the base reader every time a reference to it is required.
    /// </remarks>
    public static SqlDataReader AsSqlDataReader(this IDataReader reader)
    {
        return (SqlDataReader)(((RefCountingDataReader)(reader)).InnerReader);
    }
}

...然后使用SQLReader读取数据,执行以下操作:

using (IDataReader reader = db.ExecuteReader(command))
{
    while (reader.Read())
    {
        reader.GetInt32(reader.GetOrdinal("SomeColumn")),
        reader.GetInt32(reader.GetOrdinal("SomeOtherColumn")),
        reader.GetInt32(reader.GetOrdinal("SomeFurtherColumn")),
        // Obtain the SQL data reader each time it is used
        // (Note that GetDateTimeOffset is not on the standard IDataReader)
        reader.AsSqlDataReader().GetDateTimeOffset(reader.GetOrdinal("SQLSpecificColumn"))
        reader.AsSqlDataReader().GetDateTimeOffset(reader.GetOrdinal("AnotherSQLSpecificColumn"))
        reader.GetString(reader.GetOrdinal("SomeAdditionalColumn"))
    }
}

答案 4 :(得分:0)

我认为我有一个有效的解决方案。

enter code here

    ' Create the Database object, using the default database service. The
    ' default database service is determined through configuration.
    Dim db As Microsoft.Practices.EnterpriseLibrary.Data.Database = EnterpriseLibraryContainer.Current.GetInstance(Of Microsoft.Practices.EnterpriseLibrary.Data.Database)(DatabaseName)

    Dim dbCommand As DbCommand
    dbCommand = db.GetStoredProcCommand(StoredProcedureName)

    'create a new database connection based on the enterprise library database connection
    Dim dbConnection As System.Data.Common.DbConnection
    dbConnection = db.CreateConnection
    dbConnection.Open()

    'set the dbCommand equal to the open dbConnection
    dbCommand.Connection = dbConnection

    'return a ADO sqlDatareader but still managed by the EnterpriseLibrary
    Return dbCommand.ExecuteReader(CommandBehavior.CloseConnection)

答案 5 :(得分:0)

您应该使用界面,而不是具体的类。

Public Function AssignedDepartmentDetail(ByVal Did As Integer) As IDataReader
    Dim reader As IDataReader
    Dim Command As SqlCommand = db.GetSqlStringCommand("select seomthing from somewhere where something = @did")
    db.AddInParameter(Command, "@did", Data.DbType.Int32, Did)
    reader = db.ExecuteReader(Command)
    reader.Read()
    Return reader
End Function

和用法。就个人而言,我永远不会在表示层页面中使用datareader,但我猜他自己也不会。

Private Const TemplateFileName_Select_Column_Ordinal As Integer = 0
Private Const Id_Select_Column_Ordinal As Integer = 1

Private Sub DoSomething()
dim reader as IDataReader
reader = includes.AssignedDepartmentDetail(Did)
If reader.HasRows Then
    TheModule = reader(TemplateFileName_Select_Column_Ordinal)
    PageID = reader(Id_Select_Column_Ordinal)
Else
    TheModule = "#"

    reader.Close()  ''Dude, close your reader(s)

End If