Инъекция зависимостей с массивным ORM: динамическая проблема
Я начал работать над проектом MVC 3, которому нужны данные из огромной существующей базы данных.
моя первая идея состояла в том, чтобы использовать EF 4.1 и создать кучу POCO для представления нужных мне таблиц, но я начинаю думать, что отображение будет слишком сложным, так как мне нужны только некоторые столбцы в некоторых таблицах. (спасибо Стивену за разъяснения в комментариях.
public interface ISession
{
DynamicModel CreateTable<T>() where T : DynamicModel, new();
dynamic Single<T>(string where, params object[] args)
where T : DynamicModel, new();
dynamic Single<T>(object key, string columns = "*")
where T : DynamicModel, new();
// Some more methods supported by Massive here
}
И вот моя реализация вышеупомянутого интерфейса:
public class MassiveSession : ISession
{
public DynamicModel CreateTable<T>() where T : DynamicModel, new()
{
return new T();
}
public dynamic Single<T>(string where, params object[] args)
where T: DynamicModel, new()
{
var table = CreateTable<T>();
return table.Single(where, args);
}
public dynamic Single<T>(object key, string columns = "*")
where T: DynamicModel, new()
{
var table = CreateTable<T>();
return table.Single(key, columns);
}
}
Проблема возникает вместе с First()
, Last()
и методы FindBy()
. Массив основан на Объекте dynamic
с именем DynamicModel
и не определяет ни один из вышеперечисленных методов; он обрабатывает их через реализацию TryInvokeMethod()
, переопределенную из DynamicObject
вместо этого:
public override bool TryInvokeMember(InvokeMemberBinder binder,
object[] args, out object result) { }
Я не знаю, как "взаимодействовать" с этими методами в моем ISession
. Как мой ISession
может обеспечить поддержку для First()
, Last()
и FindBy()
?
Другими словами, как я могу использовать Все возможности Massive и все еще быть в состоянии отделить мои классы от доступа к данным?
2 ответа:
Интерфейс
В основном у вас есть несколько вариантов интерфейса для подписи для вашего Isession's Find, Last и FindBy.
Если вы хотите сохранить тот же синтаксис с именами динамических аргументов First, Last и Find, все они должны быть геттерами и возвращать dynamic с помощью DynamicObject, реализующегоbool TryInvoke(InvokeBinder binder, object[] args, out object result)
, который даст вам тот же синтаксисdynamic Find(column:val, otherColum:otherVal)
. Вот грубый базовый пример:public class MassiveSession : ISession { ... public dynamic Find{ get { return new DynamicInvoker(this,name:"Find"); } } public class DynamicInvoker : DynamicObject{ ... public override bool TryInvoke(InvokeBinder binder, object[] args, out object result) { ... return true; } } }
Если вы хотите полностью статически определенные методы, вы просто придется сделать один параметр IDictionary или что-то еще, чтобы дать вам пары ключей.
Перенаправление вызова на массивный динамический метод
Существует два способа сделать это хорошо.
Самый простой способ-использовать фреймворк с открытым исходным кодомImpromptuInterface, который позволяет программно вызывать динамические методы так же, как компилятор c# (, включая динамические именованные параметры ).
var arg = InvokeArg.Create; return Impromptu.InvokeMember(table, "Find", arg("column", val),arg("otherColum", otherVal));
Или вы можете просто попытаться подделать параметры, входящие в
TryInvokeMember
;
Я знаю, что на этот вопрос был дан ответ - но каждый метод в Massive помечен как виртуальный, так что вы можете легко издеваться над ним. Я мог бы это предложить. Или-не беспокойтесь.
В настоящее время я делаю это в своем проекте для видео MVC3 и беру страницу из playbook Rails - предлагаю свои запросы в качестве статических методов для моих объектов и иду оттуда. Я позволил своим тестам попасть в базу данных - это совсем не замедляет процесс и довольно освобождает, чтобы избавиться от всех механизмов.
Там нет DI/IoC в рельсах, и это счастливое чувство.