Managing data connection
Avi Levin edited this page Jan 3, 2018
·
3 revisions
.NET database providers use connection pooling to work with database connections, where they take connection from pool, use it, and then release connection back to connection pool so it could be reused. When connection is not released correctly after use, connection pool will consider it still used, which will lead to two consequesnces:
- your application will create more and more connections to database, because there are no free connections to reuse from connection pool manager point of view
- at some point your application will fail to obtain connection from pool, because pool size limit reached
To avoid collection leaks you should care about how you are creating and disposing connections. There are two ways to query database with linq2db:
- using
DataConnection
class. UsingDataConnection
you can make several queries in one physical database connection, so you do not have overhead on opening and closing database connection. You should follow few simple rules:-
always dispose
DataConnection
instance (it is recommended to useusing
c# statement); - query should be executed before
DataConnection
object is disposed. From version 1.8.0 we have introduced protection from wrong usage, and you will getObjectDisposedException
trying to perform query on disposedDataConnection
instance.
-
always dispose
- using
DataContext
class.DataContext
opens and closes physical connection for each query!- Be careful with
DataContext.KeepConnectionAlive
property, if you set ittrue
, it would work the same way asDataConnection
! So we do not recommend you to set this property totrue
.
- Be careful with
using (var db = new DataConnection())
{
// your code here
}
public IEnumerable<Person> GetPersons()
{
using (var db = new DataConnection())
{
// ToList call sends query to database while we are still in using
return db.GetTable<Person>().ToList();
}
}
public IEnumerable<Person> GetPersons()
{
// ToList call sends query to database and DataContext releases connection
return new DataContext().GetTable<Person>().ToList();
}
public IQuerable<Person> GetPersons()
{
// query is not sent to database here
// it will be executed later when user will enumerate results of method
// but DataContext will handle it properly
return new DataContext().GetTable<Person>();
}
public async Task<IEnumerable<Person>> GetPersons()
{
using (var db = new DataConnection())
{
// await will suspend execution inside of using waiting for query results from ToListAsync()
// after that execution will continue and dispose `DataConnection` instance
return await db.GetTable<Person>().ToListAsync();
}
}
public IEnumerable<Person> GetPersons()
{
using (var db = new DataConnection())
{
// query will be executed only when user will enumerate method results
return db.GetTable<Person>();
}
}
// DataConnection already disposed here
// starting from linq2db 1.8.0 it will fail with ObjectDisposedException
// versions prior to 1.8.0 will execute query (if there are free connectons left) and will create leaked connection
var persons = GetPersons().ToList();
public async Task<IEnumerable<Person>> GetPersons()
{
using (var db = new DataConnection())
{
// no suspension point here, awaitable task will be returned immediately from method
// creating race conditions
return db.GetTable<Person>().ToListAsync();
}
}
// query execution will be called on disposed DataConnection
var persons = await GetPersons();