C#SqlDataReader检查表项是否存在?

时间:2014-10-14 07:16:47

标签: c# sql sql-server sqldatareader

我需要检索表并检查变量'verb'是否存在于三列中的任何一列中,然后将该特定行的值传递给Verb对象,如下所述。

但是,在此代码中,读取列的if条件会跳过条件,就好像该字段在表中不存在,即使它确实存在。有没有更好的方法来做到这一点?

public static Verb GetVerbs(string verb)
{
    List<string> Verbs = new List<string>();
    Verb v = new Verb();

    SqlConnection conn = new SqlConnection("Data Source=.;Initial Catalog=QABase;Integrated Security=True");

    try
    {
        conn.Open();
    }
    catch (Exception e)
    {
        System.Console.WriteLine(e.ToString());
    }

    try
    {
        SqlDataReader myReader = null;

        SqlCommand myCommand = new SqlCommand("select * from EnglishVerbs", conn);

        myReader = myCommand.ExecuteReader();

        while (myReader.Read())
        {
            if ((myReader["BaseForm"].ToString().ToLower().Contains(verb.ToLower())) 
                 || (myReader["PastForm"].ToString().ToLower().Contains(verb.ToLower())) 
                 || (myReader["PastPartForm"].ToString().ToLower().Contains(verb.ToLower())))
            {
                v.BaseTense = Convert.ToString(myReader["BaseForm"]);
                v.PastTense = Convert.ToString(myReader["PastForm"]);
                v.PastParticiple = Convert.ToString(myReader["PastPartForm"]);
            }
            else
            {
                //row doesnt exist
                v.BaseTense = null;
                v.PastTense = null;
                v.PastParticiple = null;
            }
        }
    }
    catch (Exception e)
    {
        System.Console.WriteLine(e.ToString());
    }

    try
    {
        conn.Close();
    }
    catch (Exception e)
    {
        System.Console.WriteLine(e.ToString());
    }

    return v;
}

3 个答案:

答案 0 :(得分:3)

为什么不直接在SQL中进行检查?您的SQL将类似于:

SELECT  BaseForm, PastForm, PastPartForm
FROM    EnglishVerbs
WHERE   @Verb IN (BaseForm, PastForm, PastPartForm);

或者如果你只想要部分匹配,那就是:

SELECT  BaseForm, PastForm, PastPartForm
FROM    EnglishVerbs
WHERE   BaseForm LIKE '%' + @Verb + '%'
OR      PastForm LIKE '%' + @Verb + '%'
OR      PastPartForm LIKE '%' + @Verb + '%';

SQL更适合处理这样的基于集合的数据,并且它避免了检索整个表的网络流量,然后循环遍历每一行。考虑到英语动词的数量,我想你不想将所有这些动词都返回给应用程序进行每次搜索!

然后你可以使用类似的东西来调用它:

public static Verb GetVerbs(string verb)
{
    Verb v = new Verb();

    string sql = @"SELECT   BaseForm, PastForm, PastPartForm
                    FROM    EnglishVerbs
                    WHERE   @Verb IN (BaseForm, PastForm, PastPartForm);";

    string connString = "Data Source=.;Initial Catalog=QABase;Integrated Security=True";
    using (var connection = new SqlConnection(connString))
    using (var command = new SqlCommand(sql, connection))
    {
        command.Parameters.Add("@Verb", SqlDbType.VarChar, 50).Value = verb;
        connection.Open();

        using (var reader = command.ExecuteReader())
        if (reader.Read())
        {
            v.BaseTense = Convert.ToString(reader["BaseForm"]);
            v.PastTense = Convert.ToString(reader["PastForm"]);
            v.PastParticiple = Convert.ToString(reader["PastPartForm"]);
        }
    }
    return v;
}

N.B。我删除了所有try/catch块,因为它们使用不当!如果必须使用try / catch,只需使用一个,并在捕获一般异常之前捕获特定的异常。如果您要打扰它,而不是将其写入控制台,那么对您的异常执行有意义的操作也是一个非常好的主意,例如记录它。

肯定一个好主意是在捕获它后退出该方法,如果您的conn.Open();的初始调用抛出异常,您的方法仍然继续使用该连接。这意味着会抛出更多异常。

粗略的轮廓可能是这样的:

try
{
    using (var connection = new SqlConnection(connString))
    using (var command = new SqlCommand(sql, connection))
    {
        command.Parameters.Add("@Verb", SqlDbType.VarChar, 50).Value = verb;
        connection.Open();

        using (var reader = command.ExecuteReader())
        if (reader.Read())
        {
            v.BaseTense = Convert.ToString(reader["BaseForm"]);
            v.PastTense = Convert.ToString(reader["PastForm"]);
            v.PastParticiple = Convert.ToString(reader["PastPartForm"]);
        }
    }
}
catch (SqlException e)
{
    //Log the exception or do something else meaningful
    throw;
}
catch (Exception e)
{
    //Log the exception or do something else meaningful
    throw;
}

答案 1 :(得分:1)

您选择所有EnglishVerbs并迭代它们。如果您发现包含动词,则执行分配,否则您分配null s。但是,当您找到动词时,不会中断循环。如果列表中的最后一个元素不包含您的动词,您可以猜测,它已被分配null。将你的循环改为:

while (myReader.Read())
{
    if ( myReader["BaseForm"].ToString().ToLower().Contains(verb.ToLower()) || 
         myReader["PastForm"].ToString().ToLower().Contains(verb.ToLower()) || 
         myReader["PastPartForm"].ToString().ToLower().Contains(verb.ToLower()) )
    {
        v.BaseTense      = Convert.ToString(myReader["BaseForm"]);
        v.PastTense      = Convert.ToString(myReader["PastForm"]);
        v.PastParticiple = Convert.ToString(myReader["PastPartForm"]);

        break;
    }
    else
    {
        v.BaseTense = null;
        v.PastTense = null;
        v.PastParticiple = null;
    }
}        

此外,您不必每次都在null块中分配else。只需在循环之前分配一次。像:

v.BaseTense = null;
v.PastTense = null;
v.PastParticiple = null;

while (myReader.Read())
{
    if ( myReader["BaseForm"].ToString().ToLower().Contains(verb.ToLower()) || 
         myReader["PastForm"].ToString().ToLower().Contains(verb.ToLower()) || 
         myReader["PastPartForm"].ToString().ToLower().Contains(verb.ToLower()) )
    {
        v.BaseTense      = Convert.ToString(myReader["BaseForm"]);
        v.PastTense      = Convert.ToString(myReader["PastForm"]);
        v.PastParticiple = Convert.ToString(myReader["PastPartForm"]);

        break;
    }
} 

但是这不是最好的事情。我根据你的编程风格回答。但是,最好通过在GarethD的答案中更改查询来在数据库端进行过滤。通过这种方式,您可以从数据库中获得更少的元素,这在性能方面是一个巨大的收获。在项目级别(客户端 - 应用程序 - 数据库级别)之间传递数据应该是您最关心的问题。

答案 2 :(得分:1)

您可以对发布的代码进行一些改进。

首先,让数据库完成查找行的工作是有意义的:

SqlCommand myCommand = new SqlCommand("select * from EnglishVerbs where BaseForm = @VerbToFind or PastForm = @VerbToFind or PastPartForm = @VerbToFind", conn);
myCommand.Parameters.AddWithValue("VerbToFind", verb.ToLower());

通过这种方式,您可以告诉数据库查找至少有一列包含您要使用的动词的行。取决于您可能需要处理区分大小写的列的collation。假设您在数据库中将动词存储为小写,则上述操作应该有效。请注意,可能会找到多行。

您也应该更改错误处理,并且还应该在IDisposable子句中包装using对象。这意味着一旦完成对象,即使发生异常,它们也会自动清理:

try 
{
    using(SqlConnection conn = new SqlConnection("Data Source=.;Initial Catalog=QABase;Integrated Security=True")
    {
        conn.open();
        using(SqlCommand myCommand = new SqlCommand("select * from EnglishVerbs where BaseForm = @VerbToFind or PastForm = @VerbToFind or PastPartForm = @VerbToFind", conn))
        {
            myCommand.Parameters.AddWithValue("VerbToFind", verb.ToLower());
            using(myReader = myCommand.ExecuteReader())
            {
                 while (myReader.Read())
                 {
                     v = new Verb();
                     v.BaseTense = Convert.ToString(myReader["BaseForm"]);
                     v.PastTense = Convert.ToString(myReader["PastForm"]);
                     v.PastParticiple = Convert.ToString(myReader["PastPartForm"]);
                     verbsToReturn.Add(v);
                 }
            }
        }
    }
}
catch(Exception e)
{
    System.Console.WriteLine(e.ToString());
    throw; //Rethrow exception to let caller know that something went wrong
}

整个事情可能看起来像这样:

public static IEnumerable<Verb> GetVerbs(string verb)
{
    if (verb == null)
        throw new ArgumentException("verb cannot be null");
    List<Verb> verbsToReturn = new List<Verb>();
    Verb v = null;

    try 
    {
        using(SqlConnection conn = new SqlConnection("Data Source=.;Initial Catalog=QABase;Integrated Security=True")
        {
            conn.open();
            using(SqlCommand myCommand = new SqlCommand("select * from EnglishVerbs where BaseForm = @VerbToFind or PastForm = @VerbToFind or PastPartForm = @VerbToFind", conn))
            {
                myCommand.Parameters.AddWithValue("VerbToFind", verb.ToLower());
                using(myReader = myCommand.ExecuteReader())
                {
                     while (myReader.Read())
                     {
                         v = new Verb();
                         v.BaseTense = Convert.ToString(myReader["BaseForm"]);
                         v.PastTense = Convert.ToString(myReader["PastForm"]);
                         v.PastParticiple = Convert.ToString(myReader["PastPartForm"]);
                         verbsToReturn.Add(v);
                     }
                }
            }
        }
    }
    catch(Exception e)
    {
        System.Console.WriteLine(e.ToString());
        throw; //Rethrow exception to let caller know that something went wrong
    }

    return verbsToReturn;
}