2008-09-15 20 views
8

Un proyecto en el que estoy trabajando actualmente implica la refacturación de un objeto C# Com que sirve como una capa de acceso a la base de datos en algunas bases de datos Sql 2005.¿La mejor manera de construir consultas SQL dinámicas en C# /. NET3.5?

El autor del código existente ha construido todas las consultas sql manualmente utilizando una cadena y muchas instrucciones if para construir la declaración sql bastante compleja (~ 10 uniones,> 10 sub selecciones, ~ 15-25 donde las condiciones y GroupBy) La tabla base siempre es la misma, pero la estructura de las uniones, las condiciones y las agrupaciones depende de un conjunto de parámetros que se pasan a mi clase/método.

Construir la consulta sql de esta manera funciona, pero obviamente no es una solución muy elegante (y bastante difícil de leer/entender y mantener también) ... Podría escribir un simple "generador de consultas" pero yo estoy bastante seguro de que no soy el primero con este tipo de problema, de ahí mis preguntas:

  • ¿Cómo se construir las consultas de bases de datos?
  • ¿C# ofrece una manera fácil de generar consultas dinámicamente?

Respuesta

9

Solía ​​C# y LINQ para hacer algo similar para obtener entradas filtradas en la entrada del usuario ingrese (ver Conditional Linq Queries):

IQueryable<Log> matches = m_Locator.Logs; 

// Users filter 
if (usersFilter) 
    matches = matches.Where(l => l.UserName == comboBoxUsers.Text); 

// Severity filter 
if (severityFilter) 
    matches = matches.Where(l => l.Severity == comboBoxSeverity.Text); 

Logs = (from log in matches 
     orderby log.EventTime descending 
     select log).ToList(); 

Editar: La consulta no se realiza hasta que aparezca .ToList() en la última instrucción.

+1

¿Cómo son un grupo de declaraciones IF una consulta dinámica? –

+0

El IQueryable se convierte a SQL en la última línea, donde la consulta se ejecuta realmente; all Donde las declaraciones LINQ se convierten en una cláusula SQL WHERE. Esta es la forma en que hago SQL altamente variable también. Es mucho más limpio que tratar de escribir un proceso almacenado para hacerlo. –

+0

@Kyralessa: Gracias por la explicación. –

1

LINQ es el camino a seguir.

1

Esta es la forma en que lo haría:

public IQueryable<ClientEntity> GetClients(Expression<Func<ClientModel, bool>> criteria) 
    { 
     return (
      from model in Context.Client.AsExpandable() 
      where criteria.Invoke(model) 
      select new Ibfx.AppServer.Imsdb.Entities.Client.ClientEntity() 
      { 
       Id = model.Id, 
       ClientNumber = model.ClientNumber, 
       NameFirst = model.NameFirst, 
       //more propertie here 

      } 
     ); 
    } 

El parámetroexpresión se pasa en será la consulta dinámica que va a construir con los diferentes cláusulas WHERE, UNE, etc. Esta expresión obtendrá invocado en tiempo de ejecución y le dará lo que necesita.

Aquí hay un ejemplo de cómo llamarlo:

public IQueryable<ClientEntity> GetClientsWithWebAccountId(int webAccountId) 
    { 
     var criteria = PredicateBuilder.True<ClientModel>(); 
     criteria = criteria.And(c => c.ClientWebAccount.WebAccountId.Equals(webAccountId)); 
     return GetClients(criteria); 
    } 
1

Su vale la pena considerar si se puede poner en práctica como un procedimiento strored parametrizado y optimizarlo en la base de datos en lugar de generar dinámicamente el SQL a través de LINQ o un ORM en tiempo de ejecución A menudo esto funcionará mejor. Sé que es un poco anticuado, pero a veces es el enfoque más efectivo.

+0

Sí, ya hemos investigado eso pero en realidad no funciona ya que nuestras consultas cambian a mucho ... – Ben

0

Si usa C# y .NET 3.5, con la adición de MS SQL Server, entonces LINQ to SQL es definitivamente el camino a seguir. Si está utilizando otra cosa que no sea esa combinación, recomendaría una ruta ORM, como nHibernate o Subsonic.

+0

Linq a SQL es entonces :) – Ben

2

A menos que el tiempo de ejecución sea realmente importante, consideraría refactorizar la lógica de negocios que (con tanta frecuencia) tiende a encontrar su camino hacia la capa de datos y hacia proclos almacenados de muchos millones de años. En términos de capacidad de mantenimiento, editabillity y appendabillity, siempre trato de (como el programador C# que soy) elevar el código al businesslayer.

Tratar de resolver a alguien más El script de 8000 líneas SQL no es mi tarea favorita.

:)

// W

1

que entender el potencial de LINQ, pero todavía tengo que ver a nadie tratar de hacer una consulta LINQ de la complejidad que Ben está sugiriendo

la declaración SQL bastante compleja (~ 10 uniones,> 10 selecciones secundarias, ~ 15-25 donde las condiciones y GroupBy)

¿Alguien tiene ejemplos de Li grande nq consultas, y cualquier comentario sobre su capacidad de administración?

+0

Probablemente voy a dedicar un tiempo a tratar de reducir la complejidad ... – Ben

1

estoy viniendo a esta tardía y no tienen ninguna posibilidad para un upvote, pero hay una gran solución que no he visto considerar: una combinación de procedimiento/función con linq-to-object. O a-xml o a-datatable, supongo.

He estado esto en esta situación exacta, con una consulta masiva de construcción dinámica que fue un logro impresionante, pero cuya complejidad hizo una pesadilla de mantenimiento. Tenía tantos comentarios verdes para ayudar a la pobre savia que tenía que venir más tarde y entenderlo. Estaba en asp clásico así que tenía pocas alternativas.

Lo que he hecho desde entonces es una combinación de función/procedimiento y linq. A menudo, la complejidad total es menor que la complejidad de tratar de hacerlo en un solo lugar. Pase algunos de sus criterios al UDF, que se vuelve mucho más manejable. Esto le brinda un conjunto de resultados manejable y comprensible. Aplique sus distinciones restantes usando linq.

Puede utilizar las ventajas de ambos:

  • Reducir el total de registros tanto como sea posible en el servidor; obtenga tantas combinaciones locas atendidas en el servidor . Las bases de datos son buenas en este cosas.
  • Linq (para objetar, etc.) no es tan potente, pero es excelente para expresar criterios complejos; así que úselo para varias distinciones posibles que agregan complejidad al código, pero que el DB no sería mucho mejor en el manejo. Operando en un conjunto de resultados reducido y normalizado, linq puede expresar complixity sin una gran penalización de rendimiento.

¿Cómo decidir qué criterios manejar en el db y cuál con el linq? Usa tu juicio. Si puede manejar de manera eficiente las consultas de db complejas, puede manejar esto. Parte arte, parte ciencia.

+0

Lo que dices es que el DB haga lo que es bueno? Creo que el linq KristoferA se hace es muy impresionante. Por otro lado, estoy más feliz de controlar el rendimiento de la base de datos con algunas transacciones SQL. Tenga en cuenta que la capa de abstracción de la base de datos puede ser un conjunto de clases. El enfoque de linq parece ser uno de programación genérica, pero en realidad está requiriendo que el marco de linq administre las consultas de manera óptima. Por lo tanto, aunque técnicamente impresionante, parece un poco opaco, y mis entornos de prueba ponen esto en los procesos almacenados de todos modos. –

+0

@polyglot Sí, hay una gran cantidad de factores aquí, y todos nosotros daríamos más consejos si tuviéramos más detalles. Para un motor de búsqueda complicado, hago una ** buena conjetura ** basada en mi experiencia de que es todo * rendimiento * y * mantenibilidad *. El uso de la dinámica en los ejemplos de KristoferA puede tener una penalidad de desempeño que supera su flexibilidad. Linq para los enumerables genéricos proporciona simplicidad a un costo aceptable, siempre que ya se haya realizado algún trabajo pesado. Y con lógica masivamente compleja, no confío en Linq-to-sql para configurar el trabajo de DB de manera eficiente. Aún no. –

Cuestiones relacionadas