开发者

Use EdmFunctionAttribute without exposing Entity Framework dependency/implementation details?

Is there a good way to leverage EdmFunctionAttribute without introducing a dependency on The Entity Framework/System.Data.Entity.dll?

I thought I could have an interface with a method and a concrete implementation that implements the method using EdmFunctionAttribute to map it to a database function.

I have a context interface IMyContext defined in an assembly and an Entity Framework implementation MyContext in another assembly.

public interface IMyContext
{
    double SomeFunction(double first, double second);

    // other interface details here
}

public partial class MyContext : IMyContext
{
    [EdmFunction("MyNamespace", "MyDatabaseFunction")]
    public double SomeFunction(double first, double second)
    {
        throw new NotSupportedException("This method may only be called as part of a LINQ expression.");
    }

    // rest of interface implementation here
}

I use a factory (using StructureMap behind the scenes) to get a context instance as the interface type:

using (IMyContext context = ContextFactory.GetNewContext())
{
    var results = context.Table.Select(t => context.SomeFunction(t.Col1, t.Col2)).ToList();
}

This throws a NotSupportException saying that LINQ to Entities does not recognize the method 'Double SomeFunction(Double, Double)'.

If I cast the context to the concrete implementation

using (MyContext context = ContextFactory.GetNewContext() as MyContext)
{
    ...
}

then it works, but then I am required to specify the concrete implementation, which I do not want to do.

The function doesn't 开发者_开发问答have to be a member of the context class, I just put it there for exploring.


Can you not use Generic Repository Pattern and expose IQueryable inteface as a method there, like:

IQueryable FindAll(Func<T,bool> exp);


This is not possible as Linq query builder will investigate the interface type and not the concrete class. The expression tree will contain method reference of method of interface and when you investigate attributes on the method, it will not return any attributes.

You can create an Expression Visitor and visit your expression tree and change the type from interface to concrete type.

TypeReplacer tr = new TypeReplacer();
tr.Visit(ex);

class TypeReplacer: ExpressionVisitor{
    protected override MethodCallExpression MethodCall(MethodCallExpression exp)
    {
       // compare exp.Method and 
       // replace it with concrete Type's method
       return exp;
    }
}
0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜