我的网站正在使用企业库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与读者打交道时,我是否会遇到问题?
答案 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/212973和http://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