Reputation: 2605
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.
Upvotes: 5
Views: 1601
Reputation: 35925
Can you not use Generic Repository Pattern and expose IQueryable
inteface as a method there, like:
IQueryable FindAll(Func<T,bool> exp);
Upvotes: 1
Reputation: 39936
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;
}
}
Upvotes: 0