使用大规模ORM的依赖注入:动态故障

Ser*_*eit 12 c# dependency-injection dynamic repository-pattern massive

我已经开始研究需要来自庞大的现有数据库的数据的MVC 3项目.

我的第一个想法是继续使用EF 4.1并创建一堆POCO来表示我需要的表,但我开始认为映射会变得过于复杂,因为我只需要一些表中的一些列.(感谢Steven在评论中的澄清.

所以我想我会试试Massive ORM.我通常使用工作单元实现,所以我可以保持一切很好的解耦,并可以使用依赖注入.这是我对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
}
Run Code Online (Sandbox Code Playgroud)

这是我对上述界面的实现:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

问题就来用First(),Last()FindBy()方法.Massive基于一个dynamic被调用的对象DynamicModel,并没有定义任何上述方法; 它通过TryInvokeMethod()覆盖的实现来处理它们DynamicObject:

public override bool TryInvokeMember(InvokeMemberBinder binder, 
    object[] args, out object result) { }
Run Code Online (Sandbox Code Playgroud)

我对如何在我的界面中"界面"这些方法感到茫然ISession.我怎么能ISession提供支持First(),Last()FindBy()

换句话说,我如何使用Massive的所有功能,仍然可以将我的类与数据访问分离?

小智 8

我知道这个问题已得到解答 - 但是Massive中的每个方法都被标记为虚拟,因此您可以轻松地进行模拟.我可能会建议.或者 - 不要打扰.

我正在为我的MVC3视频项目做这个,并从Rails的剧本中获取一个页面 - 在我的对象上提供我的查询作为静态方法并从那里开始.我让我的测试进入数据库 - 它根本不会减慢速度,并且可以完全摆脱所有机器.

Rails中没有DI/IoC,这是一种快乐的感觉.

  • Rob,你有多少次测试?我在中型应用程序中进行了2000多次测试.如果我每次都需要永久性地刷新并击中数据库. (6认同)

jbt*_*ule 4

界面

基本上,对于 ISession 的 Find、Last 和 FindBy 签名,您有几个界面明智的选项。

如果您想与动态参数名称 First、Last 和 Find 保持相同的语法,则应该全部是 getter,并使用 Implements 的 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;          
        }

    }
}
Run Code Online (Sandbox Code Playgroud)

如果您想要完全静态定义的方法,您只需执行 IDictionary 的单个参数或其他操作即可为您提供密钥对。

将调用转发给 Massive 动态方法

也有两种方法可以做到这一点。

最简单的方法是使用开源框架ImpromptuInterface,它允许您像 C# 编译器一样以编程方式调用动态方法(包括动态命名参数)。

var arg = InvokeArg.Create;
return Impromptu.InvokeMember(table, "Find", arg("column", val),arg("otherColum", otherVal));
Run Code Online (Sandbox Code Playgroud)

或者您可以尝试伪造进入TryInvokeMember;的参数。