<分区>
这个问题不太可能帮助任何 future 的访问者;它只与一个小的地理区域、一个特定的时间点或一个非常狭窄的情况有关,这些情况并不普遍适用于互联网的全局受众。为了帮助使这个问题更广泛地适用,
visit the help center .
关闭 9 年前 。
我需要实现下面的功能
public PartyDetails GetAllPartyDetails(string name)
{
try
{
String query = "select * from [Party Details] where name=@name ";
pd = new PartyDetails();
com = new SqlCeCommand(query, con);
com.Parameters.AddWithValue("@name", name);
con.Open();
sdr = com.ExecuteReader();
while (sdr.Read())
{
pd.name = sdr.GetString(0);
}
con.Close();
return pd;
}
catch (Exception e)
{
con.Close();
throw e;
}
}
但是这个函数对我来说效率不高,因为我不需要仅仅因为查询的变化而编写不同的函数代码。
现在这是我需要的
public PartyDetails GetAllPartyDetails(string query)
{
try
{
pd = new PartyDetails();
com = new SqlCeCommand(query, con);
con.Open();
sdr = com.ExecuteReader();
while (sdr.Read())
{
pd.name = sdr.GetString(0);
}
con.Close();
return pd;
}
catch (Exception e)
{
con.Close();
throw e;
}
}
但它增加了 sql 注入(inject)的风险,因为它没有使用 com.Parameters.AddWithValue("@name", name);
。是否有任何替代方法可以通过调用来实现停止sql注入(inject)的功能。
对于那些不明白我的问题的人
例如我有另一个查询 select * from [party details] where address=@address and name=@anme
,为此我需要再次编写一个我使用 的函数com.Parameters.AddWithValue("@address", 地址);
com.Parameters.AddWithValue("@name", name);
,这简直是在浪费时间。查询可以有不同的参数数量,我需要不依赖于查询参数数量的函数。
名为“GetAllPartyDetails”的函数应该不 接受一个 sql 字符串作为参数。像这样的方法的目的是抽象出应用程序的其余部分了解或关心 sql 的需要,并简单地提供与数据库实现分开的各方详细信息的来源。它应该 接受派对名称作为参数,但如果您需要接受 sql 查询,那么您在错误的地方构建了 sql。
您需要的是一种方法,该方法不仅可以从 GetPartyDetails() 中调用,而且可以从需要来自特定数据源的数据的其他方法中调用。如果您在 GetPartyDetails 之外构建查询字符串,则需要稍微重新设计一下。
检索任何数据的方法应该是什么样的?当然它需要接受一个sql字符串。它还需要一些方法来接受参数信息。这可以像键/值对数组一样简单,但我更喜欢避免两次构建参数集合的代码。此参数也应该是必需的 ,而不是可选的或重载的,以鼓励良好的参数使用。
我目前使用这种模式,而且我非常喜欢它:
private IEnumerable<T> GetData(string sql, Action<SqlParameterCollection> addParams, Func<IDataRecord, T> translate)
{
using (var cn = new SqlConnection("connection string here"))
using (var cmd = new SqlCommand(sql, cn))
{
addParams(cmd.Parameters);
cn.Open();
using (var rdr = cmd.ExecuteReader())
{
while (rdr.Read())
{
yield return translate(rdr);
}
}
}
}
这满足了我们通用数据访问方法的所有目标。唯一让我不满意的部分是翻译委托(delegate)的需要,这并不是什么大损失,因为这是您无论如何都必须在应用程序的某个级别编写的代码。如果您不将每一行复制到该方法内的新对象,您可能会得到意想不到的结果,因此我们需要一种方法将数据记录直接转换为业务对象。
你可以这样调用它:
public string GetPartyDetailsByName(string name)
{
return GetData("select * from [Party Details] where name=@name", p =>
{
p.Add("@name", SqlDbType.NVarChar, 50).Value = name;
}, row =>
{
row.GetString(0);
}).First();
}
如果您有另一个带参数的查询,您可以这样调用它:
public string GetPartyDetailsByNameAddress(string name, string address)
{
return GetData("select * from [Party Details] where name=@name and address=@address", p =>
{
p.Add("@name", SqlDbType.NVarChar, 50).Value = name;
p.Add("@address", SqlDbType.NVarChar,200).Value = address;
}, row =>
{
row.GetString(0);
}).First();
}
不接受任何参数的方法如下所示:
public IEnumerable<string> GetAllPartyDetails()
{
return GetData("select * from [Party Details]", p => {}, row =>
{
row.GetString(0);
});
}
有点尴尬,但这就是重点。您希望人们慎重 不使用参数,这样他们就会情不自禁地以正确的方式使用参数。
我知道您想避免编写两种方法,但这是处理数据访问的正确 方式 。是的,有一种方法可以与数据库对话,以帮助抽象出一些样板代码。但是为每个 sql 查询添加一个方法仍然是正确的做法。
您不需要完全遵循我的 GetData() 方法:函数式风格对某些人来说有点过分。但是您确实需要一个单一的方法,它是唯一可以向您的数据库发送查询的地方,并且该方法必须 具有某种接受参数数据的机制。其他方法应该不 传递 sql。这会导致注入(inject)问题。
您询问数据的每个问题都属于它自己的方法。理想情况下,这些方法聚集在一个类中,或者一组类聚集在一个项目中以用于更大的应用程序。