2010-05-10 7 views
5

¿Hay una buena manera de aprovechar EdmFunctionAttribute sin introducir una dependencia en The Entity Framework/System.Data.Entity.dll?¿Utiliza EdmFunctionAttribute sin exponer los detalles de dependencia/implementación de Entity Framework?

Pensé que podría tener una interfaz con un método y una implementación concreta que implemente el método usando EdmFunctionAttribute para asignarlo a una función de base de datos.

Tengo una interfaz de contexto IMyContext definida en un ensamblaje y una implementación de Entity Framework MyContext en otro ensamblaje.

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 
} 

utilizo una fábrica (utilizando StructureMap detrás de las escenas) para obtener una instancia de contexto como el tipo de interfaz:

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

Esto arroja una NotSupportException diciendo que LINQ a Entidades no reconoce el método ' Double SomeFunction (Double, Double) '.

Si yo echo el contexto de la aplicación concreta

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

entonces funciona, pero luego se me requiere que especifique la aplicación concreta, que no quiero hacer.

La función no tiene que ser un miembro de la clase de contexto, simplemente la puse allí para explorar.

+0

Me encuentro en la misma situación. Yo también esperaba que EdmFunctionAttribute se resolviera cuando se accede a través de una referencia de interfaz, pero fue en vano. Se vuelve aún más difícil cuando se trabaja con contextos múltiples (bases de datos múltiples). – kdawg

+0

Por lo que vale, no pude resolver este problema y tuve que darle una bofetada a la función DB en la implementación concreta de mi Repositorio (Contexto en su caso), lo que significa que todas las llamadas a funciones deben residir dentro de mi clase de Repositorio, es decir: mi el código del cliente no pudo acceder a él directamente. No me entusiasma, pero funciona (y obliga a consultar el código a residir dentro del Repositorio, que algunos dirían que es donde pertenece). – kdawg

Respuesta

0

Esto no es posible como generador de consultas LINQ investigará el tipo de interfaz y no la clase concreta. El árbol de expresiones contendrá la referencia del método de método de la interfaz y cuando investigue atributos en el método, no devolverá ningún atributo.

Puede crear un Visitante de expresiones y visitar su árbol de expresiones y cambiar el tipo de interfaz a tipo concreto.

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

Lo sentimos, su respuesta no resuelve nada que no haya sido implementado en la pregunta. Su solución aún requiere una referencia a la clase de contexto concreto en lugar de la interfaz de contexto. – GWB

+0

He actualizado mi respuesta. –

Cuestiones relacionadas