レガシーシステムに Entity Framework(EF)を統合する際、Glimpse.Ado.AlternateType.GlimpseDbConnection 型のオブジェクトを System.Data.SqlClient.SqlConnection にキャストできないというエラーに遭遇した。この問題の原因と対処法を記録する。
発生したエラー
以下のような LINQ クエリを実行した際に例外がスローされた:
var file = _ctx.FileInfo.FirstOrDefault(t => t.ID == uid);
主なエラーメッセージは以下の通り:
Unable to determine the provider name for provider factory of type 'System.Data.SqlClient.SqlClientFactory'.
...
InvalidCastException: 無法将类型为"Glimpse.Ado.AlternateType.GlimpseDbConnection"的对象强制转换为类型"System.Data.SqlClient.SqlConnection"。
原因分析
この問題は、アプリケーションが Glimpse を使用しており、データベース接続が内部的に GlimpseDbConnection にラップされていることに起因する。EF はこのラップされた接続を直接処理できず、特に SqlCommand.DbConnection プロパティに代入する際に型変換エラーが発生する。
また、接続文字列がコード上で動的に生成されており、web.config の <connectionStrings> セクションに providerName="System.Data.SqlClient" を明示的に記述していないため、EF がプロバイダーを正しく識別できない状態となっていた。
解決策
接続オブジェクトを生成する際に、DbProviderFactories を使用してファクトリから接続インスタンスを作成し、GlimpseDbConnection が返された場合はその内部接続(InnerConnection)を取り出して使用するように修正した。
public static DbConnection CreateEfCompatibleConnection(string connectionString)
{
var factory = DbProviderFactories.GetFactory("System.Data.SqlClient");
var connection = factory.CreateConnection();
connection.ConnectionString = connectionString;
// Glimpse が有効な場合、接続は GlimpseDbConnection でラップされる
if (connection is GlimpseDbConnection glimpseConn)
{
return glimpseConn.InnerConnection as SqlConnection;
}
return connection;
}
このメソッドで取得した SqlConnection インスタンスを、DbContext のコンストラクタまたは Database.Connection に設定することで、EF は正常に SQL Server プロバイダーを認識し、クエリを実行できるようになった。
補足
この対応により、Glimpse の監視機能を維持しつつ、EF の動作も確保できる。ただし、InnerConnection へのキャストは Glimpse の内部実装に依存するため、将来のバージョンアップで破壊的変更が入る可能性がある点に注意が必要である。