的實體SqlDataReader可以由整數和字串索引(見下文:)reader[col]。所以,我希望包裝函式同時接受List<string>和List<int>作為引數。不過,我真的不想在運行時進行型別檢查,而且由于 C# 沒有型別聯合之類的東西,我認為多載是允許函式接受不同型別而不涉及泛型和運行時型別的最佳方法-檢查。
所以......我可以輕松地復制方法List<int>而不是List<string>并以這種方式多載它,但我不希望(也不應該)重復這樣的代碼。一定會有更好的辦法。
public List<List<object>> Query(string query, List<string> relevantColumns)
{
var rows = new List<List<object>>();
using (SqlConnection connection =
new SqlConnection(this.ConnectionString))
{
var command = new SqlCommand(query, connection);
command.Connection.Open();
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
List<object> row = (from col
in relevantColumns
select reader[col]).ToList();
rows.Add(row);
}
}
}
return rows;
}
uj5u.com熱心網友回復:
List<object>我們可以更進一步,創建特定目標型別的集合,而不是要求 a 中的列。例如,假設您正在查詢一個Employee表,并且您需要Employee用 EmployeeNumber、FirstName 和 LastName 的列填充一個物件。該類如下所示:
public class Employee
{
public int EmployeeNumber {get; set;}
public string FirstName {get;set;}
public string LastName {get;set;}
}
你有這樣的查詢:
SELECT *
FROM Employee
WHERE HireDate<=current_timestamp and COALESCE(TermDate,'29991231') > current_timestamp
我們可以做一個這樣的基本方法:
private IEnumerable<T> GetData<T>(string SQL, Func<IDataRecord, T> translate, Action<SqlParameterCollection> addParams)
{
using var con = new SqlConnection(this.ConnectionString);
using var cmd = new SqlCommand(SQL, con);
if(addParams is object) addParams(cmd.Parameters);
con.Open();
using var rdr = cmd.ExecuteReader();
while(rdr.Read())
{
yield return translate(rdr);
}
rdr.Close();
}
注意該方法是私有的。現在我們還添加一個這樣的公共方法:
public IEnumerable<Employee> GetEmployees()
{
string SQL = @"
SELECT EmployeeNumber, FirstName, LastName
FROM Employee
WHERE HireDate<=current_timestamp and COALESCE(TermDate,'29991231') > current_timestamp";
return GetData(SQL, row => new Employee {
EmployeeNumber = row["EmployeeNumber"],
FirstName = row["FirstName"],
LastName = row["LastName"]
}, null);
}
現在我們已經將列映射推送到translate()lambda 中,我們得到了輸入的結果,而不僅僅是一個Object. 請注意,我還在 SQL 中指定了列串列。您應該對每個查詢都執行此操作。
讓我們再看一個使用引數 lambda 的示例:
public Employee GetEmployeeByNumber(int EmployeeNumber)
{
string SQL = @"
SELECT EmployeeNumber, FirstName, LastName
FROM Employee
WHERE EmployeeNumber = @EmployeeNumber";
return GetData(SQL, row => new Employee {
EmployeeNumber = row["EmployeeNumber"],
FirstName = row["FirstName"],
LastName = row["LastName"]
}, p => {
p.Add("@EmployeeNumber", SqlDbType.Int).Value = EmployeeNumber;
}).FirstOrDefault();
}
我們看到這如何讓我們安全地包含查詢的引數資料。原始方法實際上會迫使您撰寫不安全的代碼。
uj5u.com熱心網友回復:
你可以有第三個多載,它需要一個Func<SqlDataReader, List<object>>. 然后根據該多載呼叫其他兩個多載。就像是...
public static class SqlUtilities
{
public static List<List<object>> Query(string query, List<string> relevantColumns)
{
return Query(query, reader => (from col in relevantColumns select reader[col]).ToList());
}
public static List<List<object>> Query(string query, List<int> relevantColumns)
{
return Query(query, reader => (from col in relevantColumns select reader[col]).ToList());
}
private static List<List<object>> Query(
string query,
Func<SqlDataReader, List<object>> selector)
{
var rows = new List<List<object>>();
using (SqlConnection connection =
new SqlConnection(this.ConnectionString))
{
var command = new SqlCommand(query, connection);
command.Connection.Open();
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
List<object> row = selector(reader);
rows.Add(row);
}
}
}
return rows;
}
}
但是,在這種特定情況下,我認為解決它的更好方法是重寫query,如果這是一個選項。如果僅選擇相關列relevantColumns,則不需要名稱串列或序數串列。query
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/495748.html
