2012-01-28 11 views
5

Estoy bastante seguro de que sé que la respuesta es no, pero como último intento, pensé que haría la pregunta aquí.¿Es posible modificar manualmente una expresión IQueryable?

estoy usando código EF primero para consultar una tabla de la manera habitual

_context.Set<Foo>().Where(f => f.Bar == 999); 

que crea la siguiente expresión (que acabo de escribir esto por lo que podría estar equivocado).

{SELECT 
[Extent1].[Test] AS [Test], 
[Extent1].[Test2] AS [Test2], 
FROM [dbo].[Foo] AS [Extent1] 
WHERE 19 = [Extent1].[Bar]} 

Ahora, ¿es posible modificar manualmente esta consulta para cambiar el nombre de la tabla a, por ejemplo, Foo10? (probablemente no)

Al fallar, ¿alguien sabe de alguna manera que puedo "enlazar tarde" el nombre de la tabla en el código primero?

Probablemente se esté preguntando "¿Por qué el truco sucio?" Como de costumbre, este es un problema heredado con una base de datos que tiene algunos problemas de diseño y no se puede cambiar.

Gracias de antemano.

Ps. Soy consciente de que podría usar Database.SqlQuery, pero preferiría no hacerlo.

+0

¿por qué no tienes la tabla 'Foo10' en tu modelo también? – BrokenGlass

+0

Porque técnicamente es el mismo modelo distribuido en varias tablas. La tabla en la que están sus datos varía según el parámetro –

+0

@mjmcloug, ¿de qué manera depende? – Krizz

Respuesta

0

Esto no es algo que recomendaría, pero puede ToString() la consulta para poner la instrucción SQL en una variable y luego reemplazar el nombre de la tabla. Entonces SQL ejecuta ese SQL?

Smelly and hacky but possible?

+0

Hasta donde sé, solo es posible si está dispuesto a descartar el uso de Entity Framework, lo que significa que también puede escribir el SQL a mano. – Bevan

+0

He pensado en hacer esto. Es probable que estos datos solo se lean, por lo que podrían ser adecuados. Creo que es un poco dudoso: D –

+0

@Bevan no es un desperdicio total. Significará que podemos construir la expresión de la manera habitual y cambiarla en el último minuto en lugar de tener una nueva consulta sql para cada cláusula where que queremos –

1

Suponiendo que tiene un número razonable de tablas, las agregaría todas al modelo y crearía una interfaz común que implementarán todas las clases y luego seleccionará el modelo adecuado y usará Dynamic Linq para realizar consultas.

No estoy seguro de si esto funciona, no se han comprobado y no han trabajado con "EF-código primero", pero esto es algo que me gustaría probar:

Digamos que su mesa (s) Foo tener campos - Bar, Pub, X y dejar que X sea de la que depende la tabla respectiva?

Entonces, yo definiría interfaz:

interface IFoo 
{ 
    int Bar { get; set; } 
    string Pub { get; set; } 
    int X { get; set; } 
} 

Entonces cada mesa tendrá su clase en el modelo:

[Table("Foo1")] 
class Foo1 : IFoo 
{ 
    public int Bar { get; set; } 
    public string Pub { get; set; } 
    public int X { get; set; } 
} 

[Table("Foo2")] 
class Foo2 : IFoo 
{ 
    public int Bar { get; set; } 
    public string Pub { get; set; } 
    public int X { get; set; } 
} 

entonces se podría filtrar ellos como siguiente:

IQueryable GetAdequateFoo(int X) 
{ 
    switch (X) // you could use reflection here to dynamically call the given Set<Foo#>() 
    { 
     case 1: 
     return _context.Set<Foo1>(); 
     case 2: 
     return _context.Set<Foo2>(); 
     default: 
     return null; 
    } 
} 

IFoo GetFooByBarAndX(int bar, int X) 
{ 
    IQueryable context = GetAdequateFoo(X); 
    return context.Where("it.Bar == @0", bar).Cast<IFoo>(); 
} 

Es solo una sugerencia no probada y escrita desde la cabeza, por favor no vote abajo si estoy equivocado y señale cualquier potencial problemas personales

+0

No voy a votar por esta respuesta, es una idea bastante inteligente aplicar un método de fábrica a EF. Sin embargo, no voy a pensar, ya que también tengo clases de mapeo, así que son muchas las clases para configurarlo. ¡Idea ingeniosa! –

2

¿Por qué no usa TPT herencia en su modelo?

Similar a la respuesta de @Krizz, pero evita el uso de LINQ dinámico.

Usando su comentario:

si un parámetro particular tiene un valor de 1 mirada en foo1 si sus 2 mirada en Foo2 y así sucesivamente

lo tanto, usted podría hacer esto:

var query = ctx 
    .Foos 
    .OfMyType(value) 
    .Where(f => f.Bar == 999) // f.Bar is on the base/abstract entity. 
    .ToList(); 

Dónde OfMyType es un método de extensión personalizada en IQueryable<T>:

public static IQueryable<T> OfMyType<T>(this IQueryable<T> source, string value) 
{ 
    switch (value) 
    { 
     case "1": 
     return source.OfType<Foo1>(); 
     case "2": 
     return source.OfType<Foo2>(); 
     // etc, etc 
    } 
} 

La mayoría (si no todas) de las propiedades estarán en la entidad abstracta "Foo" y usted creará entidades derivadas para cada una de las tablas, cada una con su propia tabla de respaldo.

De esta manera, el código "consumidor" (por ejemplo, los que hacen las consultas), no necesita preocuparse por las diferentes tablas/Foo, simplemente pasan el "valor mágico" a su repositorio (con suerte su usar uno), entonces puede cambiar silenciosamente a la tabla que desee.

¿Eso funcionaría?

+0

De nuevo, esto se ve bien. Tendré que intentarlo y contactarte. Pero nuevamente mi único problema es que significa generar muchas clases que trato de evitar. Tengo que amar el legado! –

+1

+1 Es bueno simplificar mi enfoque al usar lo que ofrece framework. – Krizz

Cuestiones relacionadas