0

我发现我的 C# 应用程序使用大量样板文件执行大量查询,这使我的代码空间变得混乱。我也想避免重复,但我不确定如何编写一个通用的方法来做到这一点。

我正在使用 ODP 访问 Oracle 数据库。我不能使用 Linq,因为我们的数据仓库人员拒绝指定主键,而且对 Linq 的 ODP 支持似乎是……他们宁愿让你使用他们的平台。

我不能真正返回一个列表,因为每个查询都返回不同数量的不同类型。

string gufcode = String.Empty;
double cost = 0.0;
OracleCommand GUFCommand2 = thisConnection.CreateCommand();
String GUFQuery2 = "SELECT GUF_ID, COST_RATE FROM SIMPLE_TABLE";
GUFCommand2.CommandText = GUFQuery2;
OracleDataReader GUFReader2 = GUFCommand2.ExecuteReader();
while (GUFReader2.Read())
{
    if (GUFReader2[0/**GUF_CODE**/] != DBNull.Value)
    {
        gufcode = Convert.ToString(BUFReader2[0]);
    }
    if (GUFReader2[1/**COST_RATE**/] != DBNull.Value)
    {
        cost = Convert.ToDouble(GUFReader2[1]);
    }

    effortRatioDictionary.Add(bufcode, percentageOfEffort);
}
GUFReader2.Close();

但是确实有更多的术语和更多这样的查询。我会说 15 个左右的查询 - 有些查询返回了多达 15 个左右的字段。

到处复制/粘贴这个样板会导致很多火灾:例如,如果我不更新复制粘贴中的所有内容,我将关闭错误的阅读器(或更糟)向数据库发送不同的查询字符串。

我希望能够做这样的事情:

string gufQuery = "SELECT GUF_ID, COST_RATE FROM SIMPLE_TABLE";
List<something> gufResponse = miracleProcedure(gufQuery, thisConnection);

所以大部分样板文件都消失了。

我正在寻找简单的东西。

4

3 回答 3

1

一些提示:

IDisposable派生允许使用 using 语句更清晰的代码。

IMO 你的魔法方法应该更像这样:

List<T> list = doMagic("SIMPLE_TABLE", columns);

columns可以是一个像这样的小结构数组:

struct Column
{
    string Name;
    Type   DataType;
}

如果您经常使用相同的表/列,您可能可以使用枚举。

或者

您可以从 XNA 中的 VertexDeclaration、VertexElement、VertexElementFormat 和 VertexElementUsage 类型中获得一些灵感:http: //msdn.microsoft.com/en-us/library/bb197344

当以随机顺序处理不同数量的“输入”时,这被证明非常有用。

就我而言,我已经能够用这些东西为 OpenGL 构建一个易于使用的、类似 XNA 的框架。

关于列表的返回类型,请参阅我的第二个建议。

于 2012-07-19T15:51:16.293 回答
1

我认为你不能抽象出一个函数的主要原因是因为返回的数据每次都会不同。

这意味着每次读取的次数也会有所不同。

你可以只返回 GUFReader2 但你将失去在你想要的函数内关闭它的能力。

我会说返回一个对象数组(或列表)。

在该过程中,只需通读每一行并在关闭连接时返回列表。

您的调用函数将始终知道预期数据的顺序和顺序。它也必须转换对象数据,但无论如何您都是在此过程中执行此操作。

于 2012-07-19T14:13:29.167 回答
0

Linq 是正确的答案。我感谢上面的 David M,但我不能将其标记为正确答案,因为他只留下了评论。

我能够使用 ArrayLists 做一个半广义的方法:

    public static ArrayList GeneralQuery(string thisQuery, OracleConnection myConnection)
    {
        ArrayList outerAL = new ArrayList();

        OracleCommand GeneralCommand = myConnection.CreateCommand();
        GeneralCommand.CommandText = thisQuery;
        OracleDataReader GeneralReader = GeneralCommand.ExecuteReader();
        while (GeneralReader.Read())
        {
            for (int i = 0; i < GeneralReader.FieldCount; i++)
            {
                ArrayList innerAL = new ArrayList();

                if (GeneralReader[i] != DBNull.Value)
                {
                    innerAL.Add(GeneralReader[i]);
                }
                else
                {
                    innerAL.Add(0);
                }
                outerAL.Add(innerAL);
            }
        }
        GeneralReader.Close();

        return outerAL;
    }

调用此方法的代码如下所示:

                thisConnection.Open();

                List<ProjectWrapper> liProjectCOs = new List<ProjectWrapper>();

                String ProjectQuery = "SELECT SF_CLIENT_PROJECT.ID, SF_CLIENT_PROJECT.NAMEX, SF_CHANGE_ORDER.ID, SF_CHANGE_ORDER.END_DATE, ";
                ProjectQuery += "SF_CLIENT_PROJECT.CONTRACTED_START_DATE, SF_CHANGE_ORDER.STATUS, SF_CHANGE_ORDER.TYPE, SF_CLIENT_PROJECT.ESTIMATED_END_DATE, SF_CLIENT_PROJECT.CONTRACTED_END_DATE ";
                ProjectQuery += "FROM SF_CLIENT_PROJECT, SF_CHANGE_ORDER ";
                ProjectQuery += "WHERE SF_CHANGE_ORDER.TYPE = 'New' ";
                ProjectQuery += "AND SF_CLIENT_PROJECT.ID = SF_CHANGE_ORDER.PROJECT";
                ArrayList alProjects = GeneralQuery(ProjectQuery, thisConnection);
                foreach( ArrayList proj in alProjects ) {
                    ProjectWrapper pw = new ProjectWrapper();
                    pw.projectId = Convert.ToString( proj[0] );
                    pw.projectId = Convert.ToString(proj[0]);
                    pw.projectName = Convert.ToString(proj[1]);
                    pw.changeOrderId = Convert.ToString(proj[2]);
                    pw.newEndDate = Convert.ToDateTime(proj[3]);
                    pw.startDate = Convert.ToDateTime(proj[4]);
                    pw.status = Convert.ToString(proj[5]);
                    pw.type = Convert.ToString(proj[6]);
                    if ( Convert.ToString(proj[7]) != "0" ) // 0 returned by generalquery if null
                        pw.oldEndDate = Convert.ToDateTime(proj[7]);
                    else
                        pw.oldEndDate = Convert.ToDateTime(proj[8]);
                    liProjectCOs.Add(pw);

这里有很多明显的缺点(尽管它比我之前尝试做的要好得多)。它比我与我们的数据仓库人员重新谈判的 Linq 糟糕得多。那里有一个新人,他的帮助要大得多。

Linq 将上面的代码行数减少了 2 倍。这是我之前使用的非封装方式的 4 倍。

于 2012-07-19T19:38:33.463 回答