[英]Pass comma-separated list as string of numbers to query as list of integers for PostgreSQL db in C# using Npgsql
在我用 C# 編寫的 WinForms 項目中,我正在使用 Npgsql 框架連接到 PostgreSQL 數據庫。
我正在使用 PG 數據庫中的 DataTable 填充幾個 DGV。 我還嘗試實現一個搜索功能,當用戶啟動該功能時,它會在 DGV 的 DataTable 中搜索搜索字符串,然后根據這些結果重建 DGV。 當進程搜索 DataTable 時,它正在構建一個記錄 ID 列表(例如,“1234,2345,3456”),該列表將傳遞給 db 查詢,以僅使用與用戶搜索值匹配的記錄重新填充 DGV。
這是構建 ID 列表和數據庫查詢的搜索 function:
private void btnSearch_Click(object sender, EventArgs e)
{
string searchText = txtSearchCatsGrid.Text;
string idToAddToList = "";
string tempIdList = "";
string idListForQuery = "";
DataTable dt = ((DataTable)dgvCategories.DataSource);
string cellValue;
int rowIndex;
int columnIndex;
for (rowIndex = 0; rowIndex <= dt.Rows.Count - 1; rowIndex++)
{
for (columnIndex = 0; columnIndex <= dt.Columns.Count - 1; columnIndex++)
{
cellValue = dt.Rows[rowIndex][columnIndex].ToString();
if (searchText == cellValue)
{
// Set corresponding dgvCategories cell's background color to yellow
dgvCategories[columnIndex, rowIndex].Style.BackColor = Color.Yellow;
idToAddToList = dt.Rows[rowIndex][0].ToString();
}
}
if (!string.IsNullOrEmpty(idToAddToList) && !tempIdList.Contains(idToAddToList)) tempIdList += idToAddToList + ",";
}
if (!string.IsNullOrEmpty(tempIdList))
{
// Remove the trailing comma that was added the last time an id was added to the list
idListForQuery = tempIdList.Remove(tempIdList.Length - 1, 1);
}
Console.WriteLine("idListForQuery: " + idListForQuery);
// Refresh dgvCategories with just rows from search, using idListForQuery
string companyFilter = cboSelectCompany.Text;
string categoryFilter = cboSelectCategory.Text;
db categoriesData = new db();
if (categoryFilter == "All Categories")
{
string catsQuery = "SELECT id, category, source_company, old_value, old_desc, new_value, new_desc, reference1, reference2 " +
"FROM masterfiles.xref"+
" WHERE company_name = @company" +
" AND id IN (@idList)" +
//" AND id IN (SELECT UNNEST(@idList))" +
" ORDER BY category, old_value, source_company";
this.dtCategories = categoriesData.GetDgvData(catsQuery, companyFilter, categoryFilter, idListForQuery);
}
else
{
string catsQuery = "SELECT id, category, source_company, old_value, old_desc, new_value, new_desc, reference1, reference2 " +
"FROM masterfiles.xref" +
" WHERE company_name = @company" +
" AND category = @category" +
" AND id IN (@idList)" +
//" AND id IN (SELECT UNNEST(@idList))" +
" ORDER BY old_value, source_company";
this.dtCategories = categoriesData.GetDgvData(catsQuery, companyFilter, categoryFilter, idListForQuery);
}
dgvCategories.DataSource = this.dtCategories;
if (dtCategories.Rows.Count == 0)
{
return;
}
else
{
dgvCategories.Columns[0].Visible = false;
dgvCategories.Rows[0].Cells[0].Selected = false;
}
}
然后在我的數據庫 class 中,GetDgvData() function 看起來像這樣:
public DataTable GetDgvData(string selectQuery, string companyFilter, string categoryFilter, string idFilter)
{
using (NpgsqlConnection conn = new NpgsqlConnection(connString))
using (NpgsqlCommand cmd = new NpgsqlCommand(selectQuery, conn))
{
cmd.Parameters.Add(new NpgsqlParameter("company", companyFilter));
if (!string.IsNullOrEmpty(idFilter)) cmd.Parameters.Add(new NpgsqlParameter("idList", idFilter);
//if (!string.IsNullOrEmpty(idFilter)) cmd.Parameters.Add("idList", NpgsqlDbType.Array | NpgsqlDbType.Integer).Value = idFilter;
//if (!string.IsNullOrEmpty(idFilter)) cmd.Parameters.Add(new NpgsqlParameter("idList", "ARRAY[" + idFilter + "]"));
if (categoryFilter != "All Categories") cmd.Parameters.Add(new NpgsqlParameter("category", categoryFilter));
conn.Open();
DataSet ds = new DataSet();
using (NpgsqlDataAdapter da = new NpgsqlDataAdapter(cmd))
{
da.Fill(ds);
}
return ds.Tables[0];
}
}
我在使用該 ID 列表作為查詢中的參數時遇到了問題。
您會注意到我在兩個代碼塊中都注釋掉了幾行。 這些是傳遞列表的各種嘗試,所有這些都在da.Fill(ds);
行產生錯誤。
當我只使用查詢構建代碼中未注釋的行時, AND id IN (@idList)
和添加參數的“常規”方法, if (.string.IsNullOrEmpty(idFilter)) cmd.Parameters,Add(new NpgsqlParameter("idList"; idFilter);
,也在GetDgvData()
function 中注釋, da.Fill(ds);
處的錯誤是 NpgsqlPostgresException,“操作符不存在:integer = text'”
經過一番研究,我在查詢代碼中嘗試了UNNEST()
function 並留下了參數代碼。 當我嘗試這樣做時,我得到一個異常說 function 不存在。
經過一番研究,我發現了一個將 Array db 類型轉換為 Integer db 類型的代碼示例,這是GetDgvData()
function 參數部分中注釋代碼的第一行。 當我嘗試這樣做時,拋出的異常是“System.InvalidCastException:'無法將類型 System.String 寫入 System.Int32 的數組'”。
經過更多研究,我嘗試了GetDgvData()
function 中的第三條注釋行,它用"Array[]"
包圍了參數。 我得到的例外是,“操作員不存在:integer = text'”。 我嘗試在查詢中使用和不使用UNNEST()
function 。 沒有UNNEST()
我得到一個 Npgsql.PostgresException,“操作符不存在:integer = text'”。 使用UNNEST()
我得到 PostgresException,“函數 unnest(text) 不存在”。
我還將 ID 構建為List<>
並嘗試將其傳遞給GetDgvData()
但我沒有正確傳遞它或其他什么,因為當它到達我嘗試的行時,我在GetDgvData()
中得到了 null 引用異常對List<>
做一些事情 - 包括嘗試查看控制台中的內容。
所以我真的不知道還能從這里嘗試什么。
其他人已經在他們各自的解決方案中成功地使用了上述代碼,所以我只能假設我遺漏了一些東西,但它可能是什么,我不知道。
有很多東西要解構,所以我將嘗試將其歸結為我認為是錯誤的。 我希望這足以讓你走上正軌。
看起來您嘗試使用數組,這絕對是 go 的方式。 問題是您使用了用於離散列表的IN
。 對於數組,您需要使用ANY
。
select *
from foo
where bar in (1, 2, 3)
翻譯成
select *
from foo
where bar = any (array[1, 2, 3]) -- or shorthand any ('{1,2,3}')
其次,除非你使用動態SQL,否則如果調用綁定變量,則需要為其賦值。 反之則不成立。 因此,一旦您在 SQL 中聲明了@category
,您必須在 C# 中為其分配一個值。 解決此問題的一種可能方法是將 C# 邏輯包裝在 SQL 中——我不相信您會因此遇到任何性能損失。
您修改后的查詢將如下所示:
SELECT
id, category, source_company, old_value, old_desc, new_value, new_desc,
reference1, reference2
FROM masterfiles.xref
WHERE
company_name = @company
AND (category = @category or @category = 'All Categories')
AND id = any (@idList)
ORDER BY old_value, source_company
從那里開始,我要做的關鍵更改是將您的 Id List 作為整數數組或可以通過.ToArray() 轉換為整數數組的東西傳遞。
public DataTable GetDgvData(string selectQuery, string companyFilter,
string categoryFilter, int[] idFilter)
{
using (NpgsqlConnection conn = new NpgsqlConnection(connString))
{
using (NpgsqlCommand cmd = new NpgsqlCommand(selectQuery, conn))
{
cmd.Parameters.AddWithValue("company", NpgsqlTypes.NpgsqlDbType.Varchar,
companyFilter);
cmd.Parameters.AddWithValue("category", NpgsqlTypes.NpgsqlDbType.Varchar,
categoryFilter);
cmd.Parameters.AddWithValue("idList", NpgsqlTypes.NpgsqlDbType.Array |
NpgsqlTypes.NpgsqlDbType.Integer, idFilter);
代碼的rest是一樣的。
請原諒我對AddWithValue
的使用,我知道它在許多圈子中都被不贊成...坦率地說,我喜歡它,並且覺得反對它的 arguments 並沒有超過它的實用性,尤其是 PostgreSQL。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.