开发者

Dependency Injection with Massive ORM: dynamic trouble

I've started working on an MVC 3 project that needs data from an enormous existing database.

My first idea was to go ahead and use EF 4.1 and create a bunch of POCO's to represent the tables I need, but I'm starting to think the mapping will get overly complicated as I only need some of the columns in some of the tables. (thanks to Steven for the clarification in the comments.

So I thought I'd give Massive ORM a try. I normally use a Unit of Work implementation so I can keep everything nicely decoupled and can us开发者_如何学Ce Dependency Injection. This is part of what I have for 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
}

And here's my implementation of the above interface:

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);
    }
}

The problem comes with the First(), Last() and FindBy() methods. Massive is based around a dynamic object called DynamicModel and doesn't define any of the above method; it handles them through a TryInvokeMethod() implementation overriden from DynamicObject instead:

public override bool TryInvokeMember(InvokeMemberBinder binder, 
    object[] args, out object result) { }

I'm at a loss on how to "interface" those methods in my ISession. How could my ISession provide support for First(), Last() and FindBy()?

Put it another way, how can I use all of Massive's capabilities and still be able to decouple my classes from data access?


I know this question has been answered - but every method in Massive is marked as virtual so you can Mock it easily. I might suggest that. OR - don't bother.

I'm doing this on my project currently for the MVC3 videos and taking a page from the Rails' playbook - offer my queries as static methods on my objects and go from there. I let my tests hit the database - it doesn't slow things down at all and is quite freeing to get rid of all the machinery.

There's no DI/IoC in Rails, and it's a happy feeling.


The Interface

Basically you have a couple of options interface wise for the signature for your ISession's Find, Last and FindBy.

If you want to keep the same syntax with the dynamic argument names First, Last and Find should all be getters and return dynamic with a DynamicObject that Implements bool TryInvoke(InvokeBinder binder, object[] args, out object result) that will give you the same dynamic Find(column:val, otherColum:otherVal) syntax. Here is a rough basic example:

    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;          
        }

    }
}

If you want completely statically defined methods you are just going to have to do a single parameter of IDictionary or something to give you the key pairs.

Forwarding the call to the Massive dynamic method

There are two ways to do this as well.

The easy way is to use the open source framework ImpromptuInterface that allows you to programmatically call dynamic methods just like the c# compiler (including dynamic named parameters).

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

Or you can just try to fake the parameters coming into the TryInvokeMember;

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜