public static Decimal ExecuteScalarDec(string procName, params object[] parameters)
{
try
{
using (Database database = DatabaseFactory.CreateDatabase())
{
return (Decimal)database.ExecuteScalar(procName, parameters);
}
}
catch (Exception ex)
{
throw new Exception(procName.ToString() + " " + parameters.ToString(), ex);
}
}
Обновить
Хорошо, так как это код EnterpriseLibrary. Класс Database реализует ExecuetScalar следующим образом (другие подписи в конце концов рухнет до этого):
public virtual object ExecuteScalar(DbCommand command)
{
if (command == null) throw new ArgumentNullException("command");
using (ConnectionWrapper wrapper = GetOpenConnection())
{
PrepareCommand(command, wrapper.Connection);
return DoExecuteScalar(command);
}
}
и ConnectionWrapper удаляет соединение (конец исходного файла в ссылке), поэтому, по теории, ваш вызов должен быть в порядке и удалять соединение.
Метод GetOpenConnection() возвращает оболочку, которая удаляет соединение... за исключением случаев, когда оно существует в текущем TransactionScopeConnections
:
protected ConnectionWrapper GetOpenConnection(bool disposeInnerConnection)
{
DbConnection connection = TransactionScopeConnections.GetConnection(this);
if (connection != null)
{
return new ConnectionWrapper(connection, false);
}
return new ConnectionWrapper(GetNewOpenConnection(), disposeInnerConnection);
}
А вот как TransactionScopeConnections
возвращает соединение:
public static DbConnection GetConnection(Database db)
{
Transaction currentTransaction = Transaction.Current;
if (currentTransaction == null)
return null;
Dictionary<string, DbConnection> connectionList;
DbConnection connection;
lock (transactionConnections)
{
if (!transactionConnections.TryGetValue(currentTransaction, out connectionList))
{
// We don't have a list for this transaction, so create a new one
connectionList = new Dictionary<string, DbConnection>();
transactionConnections.Add(currentTransaction, connectionList);
// We need to know when this previously unknown transaction is completed too
currentTransaction.TransactionCompleted += OnTransactionCompleted;
}
}
lock (connectionList)
{
// Next we'll see if there is already a connection. If not, we'll create a new connection and add it
// to the transaction's list of connections.
// This collection should only be modified by the thread where the transaction scope was created
// while the transaction scope is active.
// However there's no documentation to confirm this, so we err on the safe side and lock.
if (!connectionList.TryGetValue(db.ConnectionString, out connection))
{
// we're betting the cost of acquiring a new finer-grained lock is less than
// that of opening a new connection, and besides this allows threads to work in parallel
connection = db.GetNewOpenConnection();
connectionList.Add(db.ConnectionString, connection);
}
}
return connection;
}
Теперь, если я не ошибаюсь, TransactionsScopeConnections
всегда будет создавать новую связь для нового объекта базы данных (как в вашем случае) и хранить их во внутреннем словаре. Объект базы данных не реализует Disposable, поэтому я теряюсь в определении того, кто именно должен очищать соединения из этого TransactionScopeConnecitons
внутреннего списка.
Мэтт, можно ли выполнить действия, описанные в этой статье об утечках CLR и посмотреть, есть ли в вашем процессе большое количество объектов базы данных? Загрузите SOS и сделайте !dumpheap -type Microsoft.Practices.EnterpriseLibrary.Data.Database
. Если вы найдете много объектов, можете ли вы проследить стек контактов на некоторых из них с помощью !gcroot <AddressOfObject>
person
Remus Rusanu
schedule
23.07.2009