我需要检索表并检查变量'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;
}
答案 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;
}