简体   繁体   English

编辑从 SQL 查询返回的值

[英]Edit the values returned from an SQL Query

For a project I am working on I have this OwnershipRole record:对于我正在处理的项目,我有以下 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; }
}
}

For getting these details I am using an sql query like so:为了获取这些详细信息,我使用了这样的 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;
    }

We are grabbing the results and putting them into a data table.我们正在抓取结果并将它们放入数据表中。 The issue I am having however is that the values from the column Status are actually strings.然而,我遇到的问题是 Status 列中的值实际上是字符串。 So I am wondering is it possible have a condition of something like:所以我想知道是否可能有这样的条件:

if (Status == "Withdrawn") {
Status == false

}

I know that won't work but is there a way I can manipulate the values that I get from the Status column in order to fit in with the bool parameter in the OwnershipRole class?我知道这行不通,但是有没有一种方法可以操纵我从 Status 列中获得的值,以便适应 OwnershipRole 类中的 bool 参数?

Sure, either:当然,要么:

        var sql = @"
SELECT ItemID, Title, CASE WHEN Status='Withdrawn' then 1 else 0 end IsWithdrawn
FROM ItemDetail";

or或者

    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();

Yes, you can well read string from RDBS and then have bool Status from it (let get rid of GetTable method):是的,您可以很好地从 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; 
  }

Here in the line在此行

 Convert.ToString(reader[2]) != "Withdrawn" 

we read the last field ( Status ) as a string which we then convert to bool by comparing to "Withdrawn"我们将最后一个字段( Status )读取为一个string ,然后通过与"Withdrawn"进行比较将其转换为bool

From the comments:来自评论:

The GetTable() method really scares me. GetTable() 方法真的让我害怕。 It practically forces you to write code that will be horribly vulnerable to sql injection.它实际上迫使您编写极易受到 sql 注入攻击的代码。

How would you improve it?你会如何改进它?

I'd do something like this:我会做这样的事情:

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);
    }
}

The first method works as-is.第一种方法按原样工作。 You don't even need to use the additional argument for simple queries if there really is no parameters.如果确实没有参数,您甚至不需要为简单查询使用附加参数。 The other two methods work like this:另外两种方法是这样工作的:

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"
        });
}

And like this:像这样:

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"
       });
}

Note the return type changes from List to IEnumerable .请注意,返回类型从List更改为IEnumerable A good rule of thumb is the keep things as an IEnumerable for as long as possible.一个好的经验法则是尽可能长时间地将事物作为IEnumerable保留。 This can reduce memory use and set you up to stream values, so in some cases you never need the entire result set in memory at all.这可以减少内存使用并使您设置为流值,因此在某些情况下,您根本不需要内存中的整个结果集。 Soon we'll want to use IAsyncEnumerable .很快我们就会想要使用IAsyncEnumerable

When you do really need a list (which is rarer than you might think), you append the ToList() call after calling the method.当您确实需要一个列表(这比您想象的要少)时,您可以调用该方法附加ToList()调用。 Especially be careful calling ToList() on the GetRows() function, as it yields the same object on each iteration.尤其要小心在GetRows()函数上调用ToList() ,因为它在每次迭代中产生相同的对象 Doing that wrong can give you a bunch of records all representing the last row.做错了会给你一堆代表最后一行的记录。

Finally, if you don't know how to use SqlParameter objects, STOP and go Google that, because it's a really huge deal .最后,如果您不知道如何使用 SqlParameter 对象,请停止并去谷歌搜索,因为这真的很重要

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM