Инъекция зависимостей с массивным ORM: динамическая проблема


Я начал работать над проектом MVC 3, которому нужны данные из огромной существующей базы данных.

моя первая идея состояла в том, чтобы использовать EF 4.1 и создать кучу POCO для представления нужных мне таблиц, но я начинаю думать, что отображение будет слишком сложным, так как мне нужны только некоторые столбцы в некоторых таблицах. (спасибо Стивену за разъяснения в комментариях.

Поэтому я решил датьмассивному Орму попробовать. Я обычно я использую единицу реализации работы, поэтому я могу держать все красиво отделенным и могу использовать инъекцию зависимостей. Это часть того, что у меня есть для Massive:
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 12

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 в рельсах, и это счастливое чувство.