2009-02-23 7 views
18

Probablemente me encargaré de portar una aplicación vb6 a C#. Esta aplicación es una aplicación de Windows que interactúa con un acceso db. El acceso a los datos está encapsulado en objetos comerciales básicos. Una clase para una mesa básicamente. Los objetos comerciales vb6 existentes leen y escriben en el DB a través de DAO. He escrito DALs y ORMs varias veces antes, pero todos se dirigieron solo a SQL Server. Éste tendrá que dirigirse al servidor de acceso y sql. En proyectos anteriores, colocaba las cadenas de SQL en las partes privadas del objeto de negocio y tal vez movía el código sql redundante, como conectar, crear comando, en una clase base común para reducir el código.¿Dónde colocas declaraciones SQL en tus proyectos de C#?

Esta vez, estoy pensando en escribir las cadenas de SQL en un archivo .settings o en algún otro archivo de texto de tipo clave/valor. Luego escribo una utilidad sql para editar este archivo y me permite ejecutar y probar las consultas parametrizadas. Estas consultas se referenciarán por nombre en el objeto comercial en lugar de incrustar el sql en el código.

Sé que un enfoque estándar es crear un DAL para cada base de datos dirigida y tener el estado de configuración que DAL utilizar. Realmente no quiero crear las dos clases DAL para cada base de datos. Parece que sería menos código si solo hiciera referencia a la consulta correcta por nombre clave y tuviera el tipo de conexión correcto.

Entonces, ¿ustedes están haciendo cosas como esta? ¿Cómo o si abordaste este problema? ¿Qué funciona mejor para usted?

Gracias!

Respuesta

24

Bueno, hay una gran cantidad de opciones - por lo que realmente depende de lo que sus necesidades más apremiantes son :-)

Un enfoque podría ser crear sentencias SQL como archivos de texto dentro de su solución VS, y marcarlas como "recurso incrustado" en la "acción de compilación". De esta manera, el SQL está incluido en el conjunto resultante, y se puede recuperar de ella en tiempo de ejecución utilizando la ResourceManifestStream del marco .NET:

private string LoadSQLStatement(string statementName) 
{ 
    string sqlStatement = string.Empty; 

    string namespacePart = "ConsoleApplication1"; 
    string resourceName = namespacePart + "." + statementName; 

    using(Stream stm = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName)) 
    { 
     if (stm != null) 
     { 
      sqlStatement = new StreamReader(stm).ReadToEnd(); 
     } 
    } 

    return sqlStatement; 
} 

Es necesario sustituir "ConsoleApplication1" con su espacio de nombres reales, en el cual los archivos de declaración sql residen. Debe hacer referencia a ellos por medio del nombre completo. A continuación, puede cargar la instrucción SQL con esta línea:

string mySQLStatement = LoadSQLStatement("MySQLStatement.sql"); 

Sin embargo, esto hace que las consultas más bien "estática", por ejemplo, no puede configurarlos ni cambiarlos en tiempo de ejecución; están integrados directamente en los bits binarios compilados. Pero, por otro lado, en VS, tiene una buena separación limpia entre su código de programa C# y las sentencias SQL.

Si necesita poder ajustarlos y modificarlos en tiempo de ejecución, los pondría en una sola tabla SQL que contiene p. Ej. una palabra clave y la consulta SQL real como campos. A continuación, puede recuperarlos según sea necesario y ejecutarlos. Dado que están en la tabla de la base de datos, también puede cambiarlos, corregirlos y modificarlos a voluntad, incluso en tiempo de ejecución, sin tener que volver a implementar toda la aplicación.

Marc

+1

He utilizado este enfoque y me gusta. A diferencia de la mayoría de las personas, no estoy de acuerdo con poder cambiar el código sobre la marcha en tiempo de ejecución, incluso declaraciones SQL simples, por lo que el hecho de que esté compilado con el ensamblado es una ventaja para mí. – Chris

+1

¡Me alegra oír que otros usuarios están utilizando y aceptando este enfoque! :-) Y estoy de acuerdo, a veces hornear cosas en tus bits compilados es una ventaja. –

+3

En lugar de namespacePart, use this.GetType(). Namespace para la versión actual, dinámica y typeof (Program) .Namespace para static. Por supuesto, cuando lo pones en la clase de programa como estático. No olvide, cuando su archivo SQL está en el directorio SQL, consulte "SQL.StatementName.sql" – Harry

1

Te diré dónde no voy a ponerlo nunca, algo que vi hecho en algún código que heredé. Fue en Java, pero se aplica a cualquier idioma

  • Una clase base que declaró protegida variables miembro estáticas para para sentencias SQL, inited en nulo, con un método get que devuelve las sentencias SQL individuales

  • Un subclase para cada servidor de base de datos compatible, con un método init que asigna a las variables miembro de la clase base

  • Varias clases de DA que utilizan el método de la clase base para recuperar las sentencias SQL

  • La clase de puesta en marcha de aplicaciones con la responsabilidad de crear el objeto de subclase correcta y llamar a su método init

Tampoco voy a entrar en explicar por qué no voy a hacer esto nunca :-)

+2

¡El lenguaje purista de OO causa pesadillas de OO como esta! ¡gracioso! – Steve

1

Un método que utilizamos es tener una clase que se conectaría a la base de datos y los métodos para llamar a los procedimientos y en el parámetro del método se proporcionaría el nombre del procedimiento. entonces todo el código SQL está en el procedimiento. usaríamos sobrecargas para los diferentes tipos de retorno

class ConnectToSQL() 
{ 
     //connectSql code (read from setting file i assume) 

     XMLDataDocument runProcedure(string procedureName); 
     int runProcedure(string procedureName); 

     //etc.... 
} 
+0

No puede haber sobrecargas que difieran solo por tipo de devolución; dará un error de compilación CS0111 – MattDavey

2

LINQ to DataSet suena como el camino a seguir para usted.

Si no has usado el .NET 3.5 antes/LINQ, te espera un gran placer. LINQ le ahorrará escribir su sql en bruto en cadenas literales y le proporcionará una forma más lógica de crear consultas.

De todos modos, comprobar este enlace a cabo para el uso de LINQ en bases de datos Access - http://msdn.microsoft.com/en-us/library/bb386977.aspx

9

Cuando realmente lo necesito, me pusieron las consultas en archivos individuales * .sql, luego incluirlos en Resources.resx. Hay una sección 'Archivos' en ella, que le permite incluir archivos de recursos incrustados.

Después de eso, puedo usar la propiedad Resources.MyQuery generada que garantiza que el recurso existe y me ahorra escribir un método de carga de recursos personalizado.

+0

También me gusta esta solución. Las propiedades generadas son útiles. – Steve

1

Si tuviera que crear aplicaciones para SQL y Access, usaría alguna interfaz IDAL, DALCommon con implementación de funcionalidad común y DALSql y DALAccess separados, heredados de DALCommon, con algunas cosas específicas, como excepciones, transacciones manejo, seguridad, etc.
Solía ​​mantener nombres de procedimientos almacenados o consultas en archivos de recursos.

0

A veces, al igual que con las aplicaciones de generación de informes personalizados, realmente necesita aceptar la desigualdad de impedancia y dar especial importancia al SQL. En estos casos, recomiendo lo siguiente: para cada módulo que contenga cadenas SQL, cree una única clase "SQL" estática para contenerlas todas. Algunas de las cadenas de SQL probablemente requerirán parámetros, por lo tanto, sea consistente y coloque cada cadena detrás de su propio método estático.

Solo hago esto para la aplicación de informes personalizados ocasionales, pero siempre funciona muy bien y me resulta refrescante y liberador. Y es muy agradable volver meses después para hacer una mejora y encontrar todo el SQL esperándote en un único archivo SQL.cs. Con solo leer ese archivo, todo vuelve y, a menudo, este es el único archivo que debe modificarse.

No veo una necesidad en estos casos para ocultar el SQL en recursos o en otro lugar. Cuando SQL es importante, entonces es importante. Curiosamente, cada vez más desarrolladores están ahora mezclando libremente SQL con C#, incluido este sitio, porque esencialmente, eso es LINQ.

Finalmente, como siempre, asegúrese de no ser susceptible a los ataques de inyección de SQL. Especialmente si la entrada del usuario está involucrada, asegúrese de que está utilizando algún tipo de parametrización y que no está utilizando la concatenación de cadenas.

0

Las soluciones de incorporación que se muestran arriba pueden no funcionar si SQL Query tiene una causa "where" similar, pero para la misma consulta la siguiente ejecución necesita PropertyID = '113' como PropertyID read-in.

0

Glad you asked! Put your sql in a QueryFirst .sql template.

es compilado automáticamente en su aplicación como un recurso incrustado, pero no me importa. Simplemente escríbelo, en una ventana de sql real, conectado a tu base de datos, con validación de sintaxis e intellisense para tablas y columnas, luego úsala, a través de los métodos Execute() generados, con intellisense para tus entradas y resultados.

descargo de responsabilidad: Escribí QueryFirst.

Cuestiones relacionadas