[英]How To Search Item In user control Panel?
當我嘗試從數據庫中搜索用戶控件中的數據時,它會搜索或過濾我在搜索文本框中鍵入的數據。 這是我用來嘗試搜索或過濾的代碼
SqlConnection cn;
SqlCommand cm;
SqlDataReader dr;
private Label name;
private Label amount;
private Label descrip;
public Form1()
{
InitializeComponent();
cn = new SqlConnection(@"Data Source=(LocalDB)");
}
private void Form1_Load(object sender, EventArgs e)
{
GetData();
}
private void GetData()
{
cn.Open();
cm = new SqlCommand("Select * from Bills where (billname) like '%" + txtSearch.Text + "%'", cn);
dr = cm.ExecuteReader();
while (dr.Read())
{
long len = dr.GetBytes(0, 0, null, 0, 0);
byte[] array = new byte[System.Convert.ToInt32(len) + 1];
dr.GetBytes(0, 0, array, 0, System.Convert.ToInt32(len));
name = new Label();
name.Text = dr["billname"].ToString();
descrip = new Label();
descrip.Text = dr["billdescrip"].ToString();
amount = new Label();
amount.Text = dr["billamount"].ToString();
}
dr.Close();
cn.Close();
}
private void txtSearch_TextChanged(object sender, EventArgs e)
{
GetData();
}
當我在 txtSearch.text 框中鍵入內容時,結果返回空並且不顯示我試圖在 txtSearch.text 框中搜索的內容。
"Select * from Bills where (billname) like '%" + txtSearch.Text + "%'"
在我看來,您有一個數據庫表Bills
,其中有一列BillName
。 操作員在 TextBox txtSearch
鍵入一些文本,並且您想要獲取具有以 TextBox 中的文本開頭的 BillName 的所有 Bill。
我在這里看到幾個問題
SQL 注入是一種可能會破壞數據庫的代碼注入技術。 SQL 注入是最常見的網絡黑客技術之一。 SQL注入是在SQL語句中放置惡意代碼
如果操作員鍵入以下文本,看看您的 Sql 文本將是什么:“John%; DROP TABLE Bills;--”
Select * from Bills where (billname) like %John%; DROP TABLE Bills; --%
你會失去所有的賬單!
解決方案:永遠不要將輸入數據添加到您的 sql 字符串中! 始終將其添加為參數!
數據庫連接是一種稀缺資源:您不應該讓它存活時間超過所需時間。 此外,如果您的 SQL 查詢遇到異常,則連接和數據讀取器不會關閉。
養成一個習慣,當一個對象實現 IDisposable 時,你應該使用 using 語句來使用它。
通過這種方式,您可以放心,無論發生什么,在 using 語句結束時,一切都會被正確刷新、寫入、關閉和處理。
SqlConnection、SqlCommand 和 SqlDataReader 應該是 GetData 的私有成員。 這樣您就可以確定沒有人可以篡改您的連接; 您隱藏了從數據庫中獲取數據的方式(SQL 和 SqLCommand,或實體框架和 LINQ?),從而使將來的更改更容易。 您的代碼的讀者不必檢查這些變量的使用位置,並且沒有人濫用它,從而使您的代碼更容易理解。 當然,這將使將 GetData 重用於其他目的成為可能。
這讓我想到了第三個改進:
在現代編程中,您越來越多地看到日期(= 模型)和數據顯示方式(= 視圖)之間的分離。
因此,您將擁有模型類:您的數據以及如何保存、再次獲取; 和查看類:您的表單。 您需要一個適配器類來使模型適應視圖:ViewModel。 這三個一起縮寫為 MVVM。 考慮做一些關於 MVVM 的背景閱讀。
我們創建了一個類,可以保存賬單(和其他項目:客戶?訂單?產品?等),然后您可以再次檢索它們,即使在您重新啟動程序之后。 類似於倉庫,存儲庫,您可以在其中存儲物品並再次取回它們。
interface IOrderRepository
{
int AddBill(Bill bill); // return Id of the Bill
Bill FindBill(int Id); // null if not found
// your GetData:
IEnumerable<Bill> FetchBillsWithNameLike(string name);
... // other methods, about Customers, Orders, etc
}
執行:
class OrderRepository : IOrderRepository
{
private string ConnectionString {get;} = @"Data Source=(LocalDB)";
private IDbConnection CreateConnection()
{
return new SqlConnection(this.ConnectionString);
}
FetchBillsWithNameLike 的實現:
public IEnumerable<Bill> FetchBillsWithNameLike(string name)
{
using (IDbConnection dbConnection = this.CreateConnection())
{
const string sqlText = "Select Id, BillName, CustomerId, ..."
+ " from Bills where (billname) like %@Name%";
using (IDbCommand = dbConnection.CreateCommand())
{
// fill the command and the parameter:
dbCommand.CommandText = sqlText;
dbCommand.AddParameterWithValue("@Name", name);
// execute the command and enumerate the result
dbConnection.Open();
using (IDatareader dbReader = dbCommand.ExecuteReader())
{
while (dbReader.Read())
{
// There is a Bill to read
Bill bill = new Bill
{
Id = dbReader.ReadInt32(0),
Name = dbReader.ReadString(1),
CustomerId = dbReader.ReadInt32(2),
...
};
yield return bill;
}
}
}
}
}
// implement rest of interface
}
多項改進:
using
語句:如果發生任何異常,所有對象都會被正確關閉和處理。最重要的變化:使用SQL參數防止惡意SQL注入。
SQL 文本中的參數通常通過前綴@
識別
使用擴展方法AddParameterWithValue ` 添加參數。 某些數據庫在 DbCommand 中將此作為方法(例如:SQLite)
在讀取獲取的數據時,我不會讀取比呼叫者想要的更多的賬單。 因此,如果他使用以下代碼給我打電話:並非所有賬單都會被讀取:
IOrderRepository 存儲庫 = ... 字符串名稱 = this.ReadName(); bool billsWithNameAvailable = repository.FetchBillsWithName(name).Any();
在這里,我的來電者只想知道是否有任何帶有該名稱的賬單。 讀者根本不會創建任何賬單。
因為 SQL 文本是Select Id, ...
並且我讀了dbReader.GetInt32[0]
等,即使在插入或重新排序表的列之后,我的代碼仍然可以工作。
好消息是,您將能夠在不使用 Form 的情況下對方法 FetchBillsWithName 進行單元測試:您可以測試如果根本沒有數據庫,或者沒有 Bills 表或空表,或者表不包含列 BillName。 或者如果輸入文本為空會發生什么。 您可以在不需要表單的情況下對各種錯誤進行單元測試。
class Form1 : ...
{
private IOrderRepository Repository {get;} = new OrderRepository();
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
GetData();
}
private void GetData()
{
string name = this.txtSearch.Txt;
foreach(Bill fetchedBill in this.Repository.FetchBillsWithNameLike(name))
{
this.ProcessBill(fetchedBill);
}
}
private void ProcessBill(Bill fetchedBill)
{
// do your stuff with the label;
}
}
因為我將模型與視圖分開,所以視圖更簡單:更容易看到真正發生的事情:您專注於表單,而不是如何以及從何處獲取數據。
在開發過程中,雖然您還沒有數據庫,但您可以創建一個虛擬存儲庫並測試您的表單:
class DummyRepository : IOrderRepository
{
private Dictionary<int, Bill> Bills {get;} = ... // fill with some sample Bills
// TODO: implement IOrderRepository, using this.Bills
}
如果稍后您決定不從數據庫獲取數據,例如從 Internet 獲取數據,則您的表單幾乎不必更改。 它仍然可以使用IOrderRepository
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.