你在哪里把SQL语句放在你的c#项目中?

时间:2009-02-23 04:49:50

标签: c# sql winforms orm data-access-layer

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

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

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

那么,你们这样做吗?你怎么会或者你有没有解决这个问题? 什么最适合你?

谢谢!

9 个答案:

答案 0 :(得分:32)

嗯,有很多选择 - 所以它真的取决于你最迫切的需求: - )

一种方法可能是在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表中。关键字和实际SQL查询作为字段。然后,您可以根据需要检索它们并执行它们。由于它们位于数据库表中,您还可以随意更改,修复,修改它们 - 即使在运行时 - 也无需重新部署整个应用程序。

马克

答案 1 :(得分:10)

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

之后,我可以使用生成的Resources.MyQuery属性来保证资源的存在,并使我免于编写自定义资源加载方法。

答案 2 :(得分:2)

LINQ to DataSet 听起来像是你的方式。

如果您在/ LINQ之前没有使用过.NET 3.5,那么您就可以享受一下。 LINQ将保存您在字符串文字中编写原始sql,并为您提供更合理的方法来创建查询。

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

答案 3 :(得分:1)

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

  • 使用返回单个SQL语句的get方法为SQL语句声明受保护的静态成员变量的基类(inited为null)

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

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

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

我也不会解释为什么我不会这样做: - )

答案 4 :(得分:1)

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

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

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

        //etc....
}

答案 5 :(得分:1)

如果我不得不为SQL和Access创建应用程序,我将使用一些IDAL接口,具有通用功能实现的DALCommon以及从DALCommon继承的单独DALSql和DALAccess,以及一些特定的东西,例如异常,事务处理,安全等。
我曾经在资源文件中保存存储过程名称或查询。

答案 6 :(得分:0)

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

我只为偶尔的自定义报告应用程序执行此操作,但它总是很好用,感觉清爽和解放。几个月后回来做一个增强,并在一个SQL.cs文件中找到等待你的所有SQL,这是非常好的。只需读取一个文件,它就会全部回来,而这通常是唯一需要更改的文件。

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

最后,与往常一样,确保您不会受到SQL注入攻击。特别是如果涉及用户输入,请确保使用某种参数化并且不使用字符串连接。

答案 7 :(得分:0)

如果SQL Query具有“where”原因,则上面显示的嵌入式解决方案可能无效,但对于同一个Query,下次运行需要PropertyID ='113',因为PropertyID是读入的。

答案 8 :(得分:0)

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

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

免责声明:我写过QueryFirst。