代码之家  ›  专栏  ›  技术社区  ›  Steve

在您的C项目中,您将SQL语句放在哪里?

  •  19
  • Steve  · 技术社区  · 15 年前

    我可能会负责将vb6应用程序移植到C。此应用程序是一个与访问数据库交互的Windows应用程序。数据访问被封装在基本业务对象中。基本上一个表一个类。现有的VB6业务对象通过DAO读写数据库。我以前写过几次DAL和ORM,但它们都只针对SQL Server。这一个需要以Access和SQL Server为目标。在以前的项目中,我将把SQL字符串放在业务对象的私有部分中,并可能将冗余的SQL代码(如连接、创建命令)移入公共的基类中以减少代码。

    这次,我考虑将SQL字符串写入.settings文件或其他键/值类型的文本文件。然后我将编写一个SQL实用工具来编辑这个文件,并允许我运行和测试参数化查询。这些查询将被业务对象中的名称引用,而不是将SQL嵌入到代码中。

    我知道一个标准的方法是为每个目标数据库创建一个DAL,并具有使用哪个DAL的配置状态。我真的不想为每个数据库创建两个DAL类。如果我只是通过keyname引用了正确的查询,并且具有适当的连接类型,那么代码似乎会更少。

    你们在做这样的事吗?你是如何解决这个问题的? 什么对你最有效?

    谢谢!

    9 回复  |  直到 8 年前
        1
  •  28
  •   marc_s Hady Salah    15 年前

    嗯,有很多选择-所以这取决于你最迫切的需求是什么:—)

    一种方法可能是在VS解决方案中创建SQL语句作为文本文件,并在“构建操作”中将其标记为“嵌入资源”。这样,SQL将包含在生成的程序集中,并且可以在运行时使用.NET框架的ResourceManifestStream从中检索:

    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;
    }
    

    您需要将“consoleapplication1”替换为SQL语句文件所在的实际命名空间。您需要通过完全限定的名称引用它们。然后您可以用此行加载SQL语句:

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

    然而,这使得查询相当“静态”,例如,您不能在运行时配置和更改它们——它们被直接烘焙到编译的二进制位中。但另一方面,在VS中,C程序代码和SQL语句之间有一个清晰的分离。

    如果您需要在运行时调整和更改它们,我会将它们放入一个单独的SQL表中,其中包含一个关键字和实际的SQL查询作为字段。然后,您可以根据需要检索它们,并执行它们。因为它们在数据库表中,所以您也可以随意更改、修复、修改它们,甚至在运行时也不必重新部署整个应用程序。

    马克

        2
  •  9
  •   Andrey Shchekin    15 年前

    当我真正需要它时,我将查询放入单个的*.sql文件中,然后将它们包含到resources.resx中。其中有一个“文件”部分,允许您包含嵌入的资源文件。

    之后,我可以使用生成的resources.myquery属性,这既保证了资源的存在,又避免了编写自定义资源加载方法。

        3
  •  2
  •   Matt Kocaj    15 年前

    交叉表查询 听起来像是你的出路。

    如果您在/linq之前没有使用.NET 3.5,那么您可以参加一次治疗。Linq将以字符串文本形式保存编写原始SQL的过程,并为创建查询提供更合理的方法。

    无论如何,请检查此链接以在Access数据库上使用LINQ- http://msdn.microsoft.com/en-us/library/bb386977.aspx

        4
  •  1
  •   Miserable Variable    15 年前

    我会告诉你我永远不会把它放在哪里,我在继承的代码中看到了一些事情。它是Java语言,但适用于任何语言。

    • 为SQL语句声明受保护静态成员变量的基类,初始值为空,使用返回单个SQL语句的get方法

    • 每个受支持的数据库服务器的子类,带有一个分配给基类成员变量的init方法

    • 使用基类方法检索SQL语句的几个DA类

    • 负责创建正确的子类对象并调用其init方法的应用程序启动类

    我也不会解释为什么我永远不会这样做。

        5
  •  1
  •   Mike    15 年前

    我们使用的一个方法是拥有一个将连接到数据库的类和调用过程的方法,并且在方法参数中,您将提供过程名称。所以所有的SQL代码都在过程中。我们将对不同的返回类型使用重载

    class ConnectToSQL()
    {
            //connectSql code (read from setting file i assume)
    
            XMLDataDocument runProcedure(string procedureName);
            int runProcedure(string procedureName);
    
            //etc....
    }
    
        6
  •  1
  •   Maksym Gontar    15 年前

    如果必须同时为SQL和Access创建应用程序,我将使用一些IDal接口、具有公共功能实现的Dalcomon,以及从Dalcomon继承的分离Dalsql和DalAccess,以及一些特定的东西,如异常、事务处理、安全性等。
    我以前把存储过程名或查询保存在资源文件中。

        7
  •  0
  •   Mike    15 年前

    有时,像定制报告应用程序一样,您真的需要接受阻抗不匹配,并特别重视SQL。在这些情况下,我建议使用以下方法:对于包含SQL字符串的每个模块,创建一个静态“SQL”类来保存它们。一些SQL字符串可能需要参数,所以要一致,并将每个字符串放在它自己的静态方法之后。

    我只为偶尔的定制报告应用程序做这个,但它总是很好的工作,感觉清新和解放。几个月后回来做一个增强,在一个SQL.cs文件中找到所有等待您的SQL,这是非常好的。仅仅通过读取一个文件,所有的文件都会返回,而且通常这是唯一需要更改的文件。

    在这些情况下,我认为不需要在资源或其他地方隐藏SQL。当SQL很重要时,它很重要。有趣的是,现在越来越多的开发人员将SQL和C_自由地混合在一起,包括我相信这个站点,因为本质上,Linq就是这样的。

    最后,和往常一样,确保您不易受到SQL注入攻击。尤其是如果涉及到用户输入,请确保使用的是某种参数化,而不是字符串串联。

        8
  •  0
  •   user2337812    11 年前

    如果SQL查询有类似“where”的原因,则上面显示的嵌入解决方案可能不起作用,但是对于同一查询,下一次运行需要propertyid='113'作为propertyid被读取。

        9
  •  0
  •   bbsimonbb    8 年前

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

    它会自动作为嵌入资源编译到你的应用程序中,但你不在乎。您只需在一个真正的SQL窗口中编写它,连接到您的数据库,对表和列进行语法验证和智能感知,然后通过生成的 Execute() 方法,并为您的输入和结果提供IntelliSense。

    免责声明:我写了queryfirst。