5

私のサイトはエンタープライズ ライブラリ v 5.0 を使用しています。主にDAAB。executecalar、executedataset などの一部の関数は期待どおりに動作しています。Readers の使用を開始すると問題が発生する

インクルードクラスにこの関数があります:

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 を介してリーダーを扱う場合、常に問題が発生しますか?

4

6 に答える 6

3

この実装には注意が必要です。Enterprise Library Codeplex サイトには、この背景を説明するスレッドがあります: http://entlib.codeplex.com/Thread/View.aspx?ThreadId=212973

Chris Tavares は、単に .InnerReader を返すのはよくないと説明しています。なぜなら、Enterprise Library による接続追跡がオフになるからです (5 月 20 日午後 5 時 39 分からの彼の回答)。ラッパーの理由は、破棄時に余分なコードを実行してクリーンアップできるようにするためです。内側のリーダーを取得して外側を捨てると、接続がリークします!"

そうです、これに対処するのは少し面倒です。私たちは同じ状況にあります。

よろしく、マイク

于 2010-06-15T19:29:41.770 に答える
1

Enterprise Libraryの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;

それが役に立てば幸い

于 2010-05-20T14:38:55.657 に答える
1

すべての DA メソッドが SqlDataReader を必要とするため、接続がリークしています。ここで、内側の RefCountingDataReader を返す必要があり、外側のリーダーを閉じることはできません。古いエンタープライズ ライブラリは、SqlDataReader を返すことで正常に動作していました。

于 2010-08-13T03:53:03.813 に答える
1

ctavars がhttp://entlib.codeplex.com/discussions/212973およびhttp://entlib.codeplex.com/discussions/211288に投稿したコメントとコードを考慮した結果、次の一般的な取得方法が得られました。 SQL データ リーダー。

一般IDataReaderに、using ステートメントで使用し、可能な場合はその参照を直接使用します。AsSqlDataReaderSQL 固有の何かが必要な場合に呼び出します。

この拡張クラスをどこかに追加します。

/// <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"))
    }
}
于 2013-07-29T19:09:18.590 に答える
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

と使用法。個人的には、プレゼンテーション層のページでデータリーダーを使用することは決してありませんが、それぞれにデータリーダーを使用していると思います。

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
于 2012-07-31T17:42:43.843 に答える
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)
于 2010-08-16T01:32:34.030 に答える