开发者

StructureMap 2.6.1, an IRepository<T> and a EFRepository<T,TContext>

开发者 https://www.devze.com 2023-03-04 07:09 出处:网络
So I thought I\'d be slick and try this.I need to pass around a context without newing it up every time AND be able to define the mappings (Entity framework) -- in order to do this I need to inherit t

So I thought I'd be slick and try this. I need to pass around a context without newing it up every time AND be able to define the mappings (Entity framework) -- in order to do this I need to inherit then override the DbContext class. I'd like to keep it plugable with any context I toss in so that's what led me to this. I got a IRepository interface that takes a (entity) with your usual suspects in it, and an implementation of it with a dependency on IContextFactory ...

public interface IContextFactory<T> where T : DbContext
{
    T Context { get; }
}

And on my "EFRepository"

public class EFRepository<T, TContext> : IRepository<T> where T : class
        where TContext : DbContext
{

    public EFRepository(IContextFactory<TContext> contextFactory)
    {
    }
}

In my mapping, I did one of these jobs ...

        x.For(typeof(IContextFactory<>)).Use(typeof(ContextFactory<>));
        x.For(typeof(IRepository<>)).Use(typeof(EFRepository<,>));

Ok cool. In my unit tests, I try it this way...

        var repository = ObjectFactory.GetInstance<EFRepository<Currency, EFContext>>();
        var repository2 = ObjectFactory.GetInstance<IRepository<Currency>>();

First one works, no problem. 2nd one, I get hit with

The number of generic arguments provided doesn't equal the arity of the generic type definitio开发者_如何学Cn. Parameter name: instantiation

I'm guessing it's because I'm not telling structuremap which generic to pass on to IRepository since I'm passing 2? How do I do that? ...can I do that?


This should be possible but it's really messy... unless someone knows of a better way.

First you need to change how you create EFRepository<,>. Using the .Use(context => ...) overload you can access the context like context.BuildStack.Current.RequestedType.GetGenericArguments() to get the generic type you want to access. Then you can new up new instance of EFRepository<,> using reflection and getting the IContextFactory from the context.

So regardless, something like

            ObjectFactory.Configure(x =>
            {
                x.For(typeof(IContextFactory<>)).Use(typeof(ContextFactory<>));
                x.For(typeof (IRepository<>)).Use(context =>
                    {
                        Type arg1 = context.BuildStack.Current.RequestedType.
                            GetGenericArguments()[0];

                        Type targetType =
                            typeof (EfRepository<,>).MakeGenericType(new[] {arg1, typeof (IContextFactory<>)});

                        return Activator.CreateInstance(targetType,
                                                        new[] {context.GetInstance(typeof (IContextFactory<>))});

                    });
                //x.For(typeof(IRepository<>)).Use(typeof(EfRepository<,>));
            });

        var repository = ObjectFactory.GetInstance<EfRepository<Currency, EfContext>>();
        var repository2 = ObjectFactory.GetInstance<IRepository<Currency>>();

Will get you most of the way there. I think you still need to properly set the generic for the second generic parameter of targetType before it will work though.

0

精彩评论

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