我正在使用Linq to SQL連接到大約2000個數據庫之一的ASP.NET MVC應用程序。我們注意到,該應用程序花費大量時間到數據庫的連接我們的分析工具,而且我懷疑這是部分原因是由於連接池碎片如下所述:http://msdn.microsoft.com/en-us/library/8xx3tyca(v=vs.110).aspxLINQ to Sql:更改每個連接的數據庫
Many Internet service providers host several Web sites on a single server. They may use a single database to confirm a Forms authentication login and then open a connection to a specific database for that user or group of users. The connection to the authentication database is pooled and used by everyone. However, there is a separate pool of connections to each database, which increase the number of connections to the server.
There is a relatively simple way to avoid this side effect without compromising security when you connect to SQL Server. Instead of connecting to a separate database for each user or group, connect to the same database on the server and then execute the Transact-SQL USE statement to change to the desired database.
我想實現這個解決方案在Linq to Sql中,所以我們有更少的開放連接,所以當我們需要時,更有可能在池中有可用的連接。爲此,我需要在Linq每次嘗試運行查詢時更改數據庫。有沒有什麼辦法可以在不重構整個應用程序的情況下完成這個任務?目前,我們只是爲每個請求創建一個數據上下文,並且該數據上下文可能會打開和關閉多個連接。每次打開連接時,我都需要告訴它要使用哪個數據庫。
我當前的解決方案或多或少像this one - 它將SqlConnection對象封裝在繼承自DbConnection的類中。這允許我重寫Open()方法並在打開連接時更改數據庫。它適用於大多數情況下確定的,但在這使得許多更新的請求,我得到這個錯誤:
System.InvalidOperationException: Transaction does not match connection
我的想法是,我會再以同樣的方式裹DbTransaction對象是什麼我的SqlConnection一樣,並確保其連接屬性將指向包裝的連接對象。修正了上述錯誤,但引入了一個新的DbCommand無法將我的包裝連接強制轉換爲SqlConnection對象的新特性。於是我也包裝了DbCommand,現在我得到了關於未初始化的DbCommand對象事務的新的令人興奮的錯誤。
總之,我覺得我追逐的是具體的錯誤,而不是真正理解正在發生的事情。我是否在這個包裝戰略的正確軌道上,還是有更好的解決方案,我錯過了?
這裏是我的三個包裝類的更有趣的部分:
public class ScaledSqlConnection : DbConnection
{
private string _dbName;
private SqlConnection _sc;
public override void Open()
{
//open the connection, change the database to the one that was passed in
_sc.Open();
if (this._dbName != null)
this.ChangeDatabase(this._dbName);
}
protected override DbTransaction BeginDbTransaction(IsolationLevel isolationLevel)
{
return new ScaledSqlTransaction(this, _sc.BeginTransaction(isolationLevel));
}
protected override DbCommand CreateDbCommand()
{
return new ScaledSqlCommand(_sc.CreateCommand(), this);
}
}
public class ScaledSqlTransaction : DbTransaction
{
private SqlTransaction _sqlTransaction = null;
private ScaledSqlConnection _conn = null;
protected override DbConnection DbConnection
{
get { return _conn; }
}
}
public class ScaledSqlCommand : DbCommand
{
private SqlCommand _cmd;
private ScaledSqlConnection _conn;
private ScaledSqlTransaction _transaction;
public ScaledSqlCommand(SqlCommand cmd, ScaledSqlConnection conn)
{
this._cmd = cmd;
this._conn = conn;
}
protected override DbConnection DbConnection
{
get
{
return _conn;
}
set
{
if (value is ScaledSqlConnection)
_conn = (ScaledSqlConnection)value;
else
throw new Exception("Only ScaledSqlConnections can be connections here.");
}
}
protected override DbTransaction DbTransaction
{
get
{
if (_transaction == null && _cmd.Transaction != null)
_transaction = new ScaledSqlTransaction(this._conn, _cmd.Transaction);
return _transaction;
}
set
{
if (value == null)
{
_transaction = null;
_cmd.Transaction = null;
}
else
{
if (value is ScaledSqlTransaction)
_transaction = (ScaledSqlTransaction)value;
else
throw new Exception("Don't set the transaction of a ScaledDbCommand with " + value.ToString());
}
}
}
}
}