问题
I need to achieve function below
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;
}
}
But this function is not efficient for me because i don't need to write different function code only just because of change in query.
Now this what i need
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;
}
}
But it increases the risk of sql injection as it is not using com.Parameters.AddWithValue("@name", name);.Is there any replacement possible for this to be achieved by calling function to stop sql injection .
For those who don't understand my question
For example i have another query select * from [party details] where address=@address and name=@anme , for this i need to again write a function in which i use com.Parameters.AddWithValue("@address", address);
com.Parameters.AddWithValue("@name", name);, Which is simply wastage of time. Query can have different no of parameter's and i need function which does not depend upon no of parameter in query.
回答1:
A function named "GetAllPartyDetails" should not accept an sql string as an argument. The purpose of a method like that would be to abstract away the need for the rest of the app to know or care about sql, and simply provide a source for party details separate from your database implementation. It should accept the name of the party as an argument, but if you need to accept an sql query, you're building your sql in the wrong place.
What you need is a method that can be called in a generic way not only from GetPartyDetails() but also from other methods that need data from your particular data source. If you're building your query string outside of GetPartyDetails, you need to re-architect that a little bit.
What should that method for retrieving any data look like? Of course it needs to accept an sql string. It also needs some way to accept parameter information. This could be as simple as an array of key/value pairs, but I prefer code that avoids the need to build up your parameter collections twice. This argument should also be required, rather than optional or overloaded, to encourage good parameter use.
I currently use this pattern, and I've become very fond of it:
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);
}
}
}
}
This meets all the goals of our generic data access method. The only part I'm not thrilled with is the need for the translation delegate, and it's not that big a loss because this is code you were going to have to write at some level of your application anyway. If you don't copy each row to a new object inside that method, you can get unexpected results, and so we need a way to translate from a datarecord to a business object right there.
You would call it like this:
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();
}
If you have another query with parameters, you would call it like this:
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();
}
A method that does not take any parameter would look like this:
public IEnumerable<string> GetAllPartyDetails()
{
return GetData("select * from [Party Details]", p => {}, row =>
{
row.GetString(0);
});
}
It's a little awkward, but that's the point. You want people to be deliberate about not using parameters, so they can't help but stumble into doing it the right way.
I know you wanted to avoid writing two methods, but this is the right way to handle your data access. Yes, have one method that talks to the database, to help abstract away some of the boilerplate code. But having an additional method for each sql query is still the right thing to do.
You don't need to follow my GetData() method exactly: the functional style is a bit much for some. But you do need a single method that is the one and only place that can send a query to your database, and this method must have some mechanism for accepting parameter data. Other methods should not be passing sql around. That leads to injection issues.
Each question you ask the data belongs in it's own method. Ideally, these methods are gathered together in a class, or group of classes gathered in a single project for larger applications.
回答2:
I suggest a combination of optional arguments and conditional logic. This is the general idea. I am not worried about syntax.
public PartyDetails GetAllPartyDetails(string name = string.Empty,
string address = string.Empty)
{
String query="select * from [Party Details] where 1=1 ";
if (name != string.Empty)
{
query = query + " and name = @name";
code to add parameter
}
repeat for all arguments
rest of function
回答3:
You need to convert this to a stored proedure which takes the name as a parameter.
Here is a good place to start reading. http://msdn.microsoft.com/en-us/library/ff648339.aspx
来源:https://stackoverflow.com/questions/16466300/sql-injection-parameterised-query