[英]Edit the values returned from an SQL Query
对于我正在处理的项目,我有以下 OwnershipRole 记录:
public record OwnershipRole
{
public OwnershipRole()
{
}
public OwnershipRole(Guid id, string title, bool isWithdrawn)
{
Id = id;
Title = title;
IsWithdrawn = isWithdrawn;
}
public Guid Id { get; set; }
public string Title { get; set; }
public bool IsWithdrawn { get; set; }
}
}
为了获取这些详细信息,我使用了这样的 sql 查询:
public List<OwnershipRole> GetOwnershipRoles()
{
var sql = @"
SELECT ItemID, Title, Status
FROM ItemDetail";
var data = GetTable(sql);
return data.Select().Select(dr => new OwnershipRole
{
Id = dr.Field<Guid>(0),
Title = dr.Field<string>(1),
IsWithdrawn = !dr.Field<bool>(2)
}).ToList();
}
private DataTable GetTable(string sql)
{
var rv = new DataTable();
using var cnn = new SqlConnection(_connectionString);
using var cmd = new SqlCommand(sql, cnn);
cnn.Open();
var da = new SqlDataAdapter(cmd);
da.Fill(rv);
cnn.Close();
return rv;
}
我们正在抓取结果并将它们放入数据表中。 然而,我遇到的问题是 Status 列中的值实际上是字符串。 所以我想知道是否可能有这样的条件:
if (Status == "Withdrawn") {
Status == false
}
我知道这行不通,但是有没有一种方法可以操纵我从 Status 列中获得的值,以便适应 OwnershipRole 类中的 bool 参数?
当然,要么:
var sql = @"
SELECT ItemID, Title, CASE WHEN Status='Withdrawn' then 1 else 0 end IsWithdrawn
FROM ItemDetail";
或者
return data.Select().Select(dr => new OwnershipRole
{
Id = dr.Field<Guid>(0),
Title = dr.Field<string>(1),
IsWithdrawn = dr.Field<string>(2)=="Withdrawn"?true:false
}).ToList();
是的,您可以很好地从 RDBS 读取string
,然后从中获取bool
Status
(摆脱GetTable
方法):
public List<OwnershipRole> GetOwnershipRoles() {
using var cnn = new SqlConnection(_connectionString);
cnn.Open();
string sql =
@"SELECT ItemID,
Title,
Status
FROM ItemDetail";
using var cmd = new SqlCommand(sql, cnn);
var result = new List<OwnershipRole>();
using var reader = cmd.OpenReader();
while (reader.Read()) {
result.Add(new OwnershipRole(
Guid.Parse(Convert.ToString(reader[0])),
Convert.ToString(reader[1]),
Convert.ToString(reader[2]) != "Withdrawn"
));
}
return result;
}
在此行
Convert.ToString(reader[2]) != "Withdrawn"
我们将最后一个字段( Status
)读取为一个string
,然后通过与"Withdrawn"
进行比较将其转换为bool
来自评论:
GetTable() 方法真的让我害怕。 它实际上迫使您编写极易受到 sql 注入攻击的代码。
你会如何改进它?
我会做这样的事情:
private DataTable GetTable(string sql, SqlParameter[] paras = null)
{
var rv = new DataTable();
using var cnn = new SqlConnection(_connectionString);
using var cmd = new SqlCommand(sql, cnn);
using var da = new SqlDataAdapter(cmd);
if (paras != null && paras.Length > 0)
{
cmd.Parameters.AddRange(paras);
}
da.Fill(rv);
return rv;
}
private IEnumerable<IDataRecord> GetRows(string sql, SqlParameter[] paras = null)
{
var rv = new DataTable();
using var cnn = new SqlConnection(_connectionString);
using var cmd = new SqlCommand(sql, cnn);
if (paras != null && paras.Length > 0)
{
cmd.Parameters.AddRange(paras);
}
cnn.Open();
using var rdr = cmd.ExecuteReader();
while (rdr.Read())
{
yield return rdr;
}
}
private IEnumerable<T> GetItems<T>(string sql, Func<IDataRecord, T> transform, SqlParameter[] paras = null)
{
var rv = new DataTable();
using var cnn = new SqlConnection(_connectionString);
using var cmd = new SqlCommand(sql, cnn);
if (paras != null && paras.Length > 0)
{
cmd.Parameters.AddRange(paras);
}
cnn.Open();
using var rdr = cmd.ExecuteReader();
while (rdr.Read())
{
yield return transform(rdr);
}
}
第一种方法按原样工作。 如果确实没有参数,您甚至不需要为简单查询使用附加参数。 另外两种方法是这样工作的:
public IEnumerable<OwnershipRole> GetOwnershipRoles()
{
var sql = @"
SELECT ItemID, Title, Status
FROM ItemDetail";
var data = GetRows(sql);
return data.Select(dr => new OwnershipRole
{
Id = (Guid)dr[0],
Title = (string)dr[1],
IsWithdrawn = ((string)dr[2])!="Withdrawn"
});
}
像这样:
public IEnumerable<OwnershipRole> GetOwnershipRoles()
{
var sql = @"
SELECT ItemID, Title, Status
FROM ItemDetail";
return GetItems<OwnershipRole>(sql, row => new OwnershipRole
{
Id = (Guid)dr[0],
Title = (string)dr[1],
IsWithdrawn = ((string)dr[2])!="Withdrawn"
});
}
请注意,返回类型从List
更改为IEnumerable
。 一个好的经验法则是尽可能长时间地将事物作为IEnumerable
保留。 这可以减少内存使用并使您设置为流值,因此在某些情况下,您根本不需要内存中的整个结果集。 很快我们就会想要使用IAsyncEnumerable
。
当您确实需要一个列表(这比您想象的要少)时,您可以在调用该方法后附加ToList()
调用。 尤其要小心在GetRows()
函数上调用ToList()
,因为它在每次迭代中产生相同的对象。 做错了会给你一堆代表最后一行的记录。
最后,如果您不知道如何使用 SqlParameter 对象,请停止并去谷歌搜索,因为这真的很重要。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.