下面是使用 Dapper.Net 在 DAL 中调用数据的示例:
/// <summary>
/// Handles db connectivity as Dapper assumes an existing connection for all functions
/// Since the app uses three databases, pass in the connection string for the required db.
/// </summary>
/// <returns></returns>
protected static IDbConnection OpenConnection(string connectionStringName)
{
try
{
connection = new SqlConnection(WebConfigurationManager.ConnectionStrings[connectionStringName].ConnectionString);
//connection = SqlMapperUtil.GetOpenConnection(connectionStringName); // if we want to use the Dapper utility methods
//connection = new SqlConnection(connectionString);
connection.Open();
return connection;
}
catch (Exception ex)
{
ErrorLogging.Instance.Fatal(ex); // uses singleton for logging
return null;
}
}
public string GetNickname(int profileID)
{
string nickname = string.Empty;
using (IDbConnection connection = OpenConnection("PrimaryDBConnectionString"))
{
try
{
var sp_nickname = connection.Query<string>("sq_mobile_nickname_get_by_profileid", new { profileID = profileID }, commandType: CommandType.StoredProcedure);
nickname = sp_nickname.First<string>();
}
catch (Exception ex)
{
ErrorLogging.Instance.Fatal(ex);
return null;
}
}
return nickname;
}
我们看到的一致错误如下:
2012-06-20 11:42:44.8903|致命|已经有一个打开的 DataReader 与此命令关联,必须先关闭。| 在 System.Data.SqlClient.SqlInternalConnectionTds.ValidateConnectionForExecute(SqlCommand 命令) 在 System.Data.SqlClient.SqlConnection.ValidateConnectionForExecute(String 方法,SqlCommand 命令) 在 System.Data.SqlClient.SqlCommand.ValidateCommand(String 方法,布尔异步) 在 System System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, DbAsyncResult result) at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method) 在系统。 Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior 行为,
在 MyApp.DAL.DapperORM.SqlMapper.d_ 131.MoveNext() in C:\Projects\Git\MyApp\MyApp.DAL\MyApp.DAL.MyAppPrimary.Repositories\Dapper\SqlMapper.cs:line 581 at System.Collections.Generic.List
1..ctor(IEnumerable1 collection) at System.Linq.Enumerable.ToList[TSource](IEnumerable
1 源) 在 MyApp.DAL.DapperORM.SqlMapper.Query[T](IDbConnection cnn, String sql, Object param, IDbTransaction transaction, Boolean buffered, Nullable1 commandTimeout, Nullable
1 commandType) 在 C:\Projects\Git\MyApp\MyApp.DAL\MyApp.DAL.MyAppPrimary.Repositories\Dapper\SqlMapper.cs:C 中 MyApp.DAL.Repositories.MemberRepository.AddNotificationEntry(NewsfeedNotification notificationEntry) 的第 538 行: \Projects\Git\MyApp\MyApp.DAL\MyApp.DAL.MyAppPrimary.Repositories\MemberRepositories\MemberRepository.cs:line 465 2012-06-20 11:42:45.2491|致命|当阅读器关闭时调用读取无效。 | 在 System.Data.SqlClient.SqlDataReader.ReadInternal(布尔 setTimeout)
在 System.Data.SqlClient.SqlDataReader.Read() 在 MyApp.DAL.DapperORM.SqlMapper.d _131.MoveNext() in C:\Projects\Git\MyApp\MyApp.DAL\MyApp.DAL.MyAppPrimary.Repositories\Dapper\SqlMapper.cs:line 597 at System.Collections.Generic.List
1..ctor(IEnumerable1 collection) at System.Linq.Enumerable.ToList[TSource](IEnumerable
1 源) 在 MyApp.DAL.DapperORM.SqlMapper.Query[T](IDbConnection cnn, String C:\Projects\Git\MyApp\MyApp.DAL\MyApp.DAL.MyAppPrimary.Repositories\Dapper\SqlMapper.cs 中的sql、对象参数、IDbTransaction 事务、布尔缓冲、可空1 commandTimeout, Nullable
1 命令类型):MyApp.DAL 的第 538 行。 DapperORM.SqlMapper.Query(IDbConnection cnn, String sql, Object param, IDbTransaction transaction, Boolean buffered, Nullable1 commandTimeout, Nullable
1 commandType) 在 C:\Projects\Git\MyApp\MyApp.DAL\MyApp.DAL.MyAppPrimary.Repositories\Dapper\SqlMapper.cs:C 中 MyApp.DAL.Repositories.MemberRepository.GetBuddies(Int32 profileID) 的第 518 行: \Projects\Git\MyApp\MyApp.DAL\MyApp.DAL.MyAppPrimary.Repositories\MemberRepositories\MemberRepository.cs:line 271 2012-06-20 11:43:01.2392|致命|序列不包含元素| 在 System.Linq.Enumerable.First[TSource](IEnumerable`1 源) 在 C:\Projects\Git\MyApp\MyApp.DAL\MyApp.DAL.MyAppPrimary 中的 MyApp.DAL.Repositories.MemberRepository.GetNickname(Int32 profileID) .Repositories\MemberRepositories\MemberRepository.cs:第 337 行
最初我将退货放在里面using {...}
并将它们移到using
街区外,但仍然遇到同样的问题。
这是一个高流量的应用程序,所以在测试这个问题直到我们上线后才真正出现。
对于使用 Dapper 进行 DataReader 管理,这里还有其他事情要做吗?
- - - 更新 - - -
我应该早点发布这个,但现在才添加这个。
Dapper.Net 的第 581 行包含ExecuteReader()
代码:
private static IEnumerable<T> QueryInternal<T>(this IDbConnection cnn, string sql, object param, IDbTransaction transaction, int? commandTimeout, CommandType? commandType)
{
var identity = new Identity(sql, commandType, cnn, typeof(T), param == null ? null : param.GetType(), null);
var info = GetCacheInfo(identity);
using (var cmd = SetupCommand(cnn, transaction, sql, info.ParamReader, param, commandTimeout, commandType))
{
using (var reader = cmd.ExecuteReader())
{
Func<Func<IDataReader, object>> cacheDeserializer = () =>
{
info.Deserializer = GetDeserializer(typeof(T), reader, 0, -1, false);
SetQueryCache(identity, info);
return info.Deserializer;
};
if (info.Deserializer == null)
{
cacheDeserializer();
}
var deserializer = info.Deserializer;
while (reader.Read())
{
object next;
try
{
next = deserializer(reader);
}
catch (DataException)
{
// give it another shot, in case the underlying schema changed
deserializer = cacheDeserializer();
next = deserializer(reader);
}
yield return (T)next;
}
}
}
...在嵌套using
代码中看到它?我想知道是否由于yield return (T)next;
while 内部的代码,嵌套的内部using
,是否会导致问题。
问题是,在流量适中的情况下,Dapper 似乎运行良好。然而,在一个每秒大约有 1000 个请求的系统中,它似乎会出错。
我想这对于 Dapper 开发者来说更像是一个仅供参考,并且想知道他们是否可以解决这个问题。
(我意识到我在代码中错过了命名 DapperORM - 它不是 ORM)