我正在Unity中创建一个游戏,该游戏允许用户输入SQL命令。

可以说我在SQL数据库中有一个名为Terminals的表,其中包含Id,Name,Type和Hacked列。

如果用户输入SELECT命令(例如SELECT Id, Name FROM Terminals;),则会在lineList中添加返回的数据字段的数量,例如仅ID和名称。

我的问题是,如何将Terminals类中的属性分配给从SQL查询返回的正确值?

这是我的代码:

public class SQLConnect : MonoBehaviour {
private void Query(string sqlCommand)
{
    using (dbCon = new SqlConnection(connectionString))
    {
        using (dbcmd = dbCon.CreateCommand())
        {
            dbcmd.CommandText = sqlCommand;
            dbCon.Open();

            using (reader = dbcmd.ExecuteReader())
            {
                var readList = new List<List<object>>();

                while (reader.Read())
                {
                    var lineList = new List<object>();

                    for (int i = 0; i < reader.FieldCount; i++)
                    {
                        lineList.Add(reader.GetValue(i)); // This reads the entries in a row
                    }

                    readList.Add(lineList);
                }
            }
        }
    }
}
}

public static class SQLDynamicData
{
    public static List<Terminals> TerminalList;

    public class Terminals
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Type { get; set; }
        public bool Hacked { get; set; }

        public Terminals(int id, string name, string type, bool hacked)
        {
            Id = id;
            Name = name;
            Type = type;
            Hacked = hacked;
        }
    }
}


这是我尝试过的:

using (reader = dbcmd.ExecuteReader())
            {
                var readList = new List<List<object>>();

                while (reader.Read())
                {
                    var lineList = new List<object>();

                    for (int i = 0; i < reader.FieldCount; i++)
                    {
                        lineList.Add(reader.GetValue(i)); // This reads the entries in a row
                    }
                 readList.Add(lineList);
                }
                foreach (var item in readList)
                {
                    SQLDynamicData.TerminalList.Add(new SQLDynamicData.Terminals(Convert.ToInt32(item[0]), item[1].ToString(), item[2].ToString(), Convert.ToBoolean(item[3])));
                }
            }


问题是,显然,如果返回的数据只是Id和Name,则item [2]和item [3]会引发异常。另外,如果用户只是选择Name而没有其他选择,则Name可能会首先返回而不是Id,在这种情况下,将item [0]转换为int是不正确的

我该怎么做呢?我需要执行此操作,因为我想基于SQL数据更新游戏对象。

最佳答案

如果您想知道查询创建的DataReader中存在哪些列,则可以使用GetSchemaTable方法,该方法返回带有列说明的表。在这种情况下,您只对列名感兴趣,因此可以使用列名创建一个简单的List<string>
这为使用List<Terminals>而不是复杂的List<List<object>>开辟了道路。

当然,我们还需要一种方法,以这种方式使Query方法尽可能通用,如果您为另一个类传递不完整的查询文本,则可以使用相同的代码。
实现此目标的一种简单方法是,从打开读取器内容的任务中分离出用于打开连接,创建命令,执行命令并遍历记录的常规内容。如果将您的DataReader和列在DataReader中的列的列表传递给Query方法,则可以实现此目的。

因此,您的查询方法更改为

private void Query(string sqlCommand, Action<SqlDataReader, List<string> loader)
{
    using (dbCon = new SqlConnection(connectionString))
    using (dbcmd = dbCon.CreateCommand())
    {
        dbcmd.CommandText = sqlCommand;
        dbCon.Open();
        DataTable dt = reader.GetSchemaTable();
        List<string> columns = dt.AsEnumerable().Select(x => x.Field<string>("COLUMNNAME")).ToList();
        using (reader = dbcmd.ExecuteReader())
        {
            while (reader.Read())
              if(loader != null)
                loader(reader, columns);
        }
    }
}


如您所见,Query方法不知道如何从查询中检索字段,但是将这个任务留给了作为其第二个参数接收的特殊方法。此方法需要两个参数,即DataReader和列名称的列表。使用它们,可以创建一个Terminals实例,提取列值(检查是否存在期望的列),然后将Terminals实例添加到Terminals的全局列表中。

然后,无论谁调用Query方法,都应提供有效加载数据的方法,例如:

private void LoadTerminalsData(SqlDataReader reader, List<string> cols)
{
    Terminals t = new Terminals();
    if(cols.IndexOf("id") != -1)
        t.id = reader.GetInt32(reader.GetOrdinal("id"));
    if(cols.IndexOf("Name") != -1)
        t.Name = reader.GetString(reader.GetOrdinal("Name"));
    if(cols.IndexOf("Type") != -1)
        t.Type = reader.GetString(reader.GetOrdinal("Type"));
    if(cols.IndexOf("Hacked") != -1)
        t.Hacked = reader.GetBoolean(reader.GetOrdinal("Hacked"));
    listOfTerminals.Add(t);
}


调用传递给Query方法的所有内容,如下所示

....Query("select id, Name from Terminals", LoadTerminalData);

关于c# - C#从未知列表长度分配字段,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/34979265/

10-11 00:17