Как часть инструмента профилирования, у меня есть собственный стек ADO.NET, который действует как «декоратор» вокруг стандартного ADO.NET, поэтому он фактически не выполняет никакой работы - он просто проходит на звонки (но с логированием и тд). Помимо прочего, я предоставил DbProviderFactory
из моего пользовательского соединения, которое реализует IServiceProvider
и предоставляет пользовательское DbProviderServices
.
Это прекрасно работает для большинства инструментов, включая LINQ-to-SQL, однако Entity Framework не в восторге.
Например - скажем, у меня есть:
MetadataWorkspace workspace = new MetadataWorkspace(
new string[] { "res://*/" },
new Assembly[] { Assembly.GetExecutingAssembly() });
using(var conn = /* my custom wrapped DbConnection */)
{
var provider = DbProviderServices
.GetProviderServices(conn); // returns my custom DbProviderServices
var factory = DbProviderServices
.GetProviderFactory(conn); // returns my custom DbProviderFactory
...
пока все хорошо - две вышеупомянутые строки работают; верная (пользовательская) информация о провайдере возвращается.
Теперь мы можем добавить модель EF:
using (var ec = new EntityConnection(workspace,conn))
using (var model = new Entities(ec))
{
count = model.Users.Count(); // BOOM!
}
терпит неудачу за исключением:
Невозможно привести объект типа «(мое пользовательское соединение)» к типу «System.Data.SqlClient.SqlConnection».
, что при назначении соединения команде; по сути, он по умолчанию провайдер sql-сервера для SSpace
, и генерирует голый SqlCommand
. Затем он пытается присвоить conn
сгенерированной команде, которая не может работать (она будет работать правильно, если все декораторы на месте, и вместо нее использовался декорированный DbCommand
).
Теперь, весь смысл оборачивать это на лету означает, что я действительно не хочу менять EDMX, чтобы зарегистрировать отдельную фабрику. Я просто хочу, чтобы он знал о моей лжи, проклятой лжи и декораторах.
Следующее работает , взламывая кишки SSpace
(установка поля private readonly
, о котором я не имею права знать или злоупотреблять):
StoreItemCollection itemCollection =
(StoreItemCollection)workspace.GetItemCollection(DataSpace.SSpace);
itemCollection.GetType().GetField("_providerFactory",
BindingFlags.NonPublic | BindingFlags.Instance)
.SetValue(itemCollection, factory);
С этим, правильный завод использует SSpace
. Однако это явно противно.
Итак: я здесь пропускаю трюк? Как я могу перехватить поставщика EF менее решительными мерами?