【问题标题】:How to convert a data reader to dynamic query results如何将数据阅读器转换为动态查询结果
【发布时间】:2015-10-17 20:46:32
【问题描述】:

我有一个视图,它通常从 WebMatrix 查询(IEnumerable<dynamic> 数据类型)中获取查询结果,并在表格中显示结果:

@model MySite.Models.Entity
@foreach(var row in Model.Data)
{
    <tr>
        @foreach (var column in row.Columns)
        {
            <td>@column<span>:</span> @row[column]</td>
        }
    </tr>
}

这是我查询数据库的模型:

public class Entity
{
    public dynamic Data {get; set; }
    public Entity(String table)
    {
        if (table == "User" || table == "Group)
        {
            WebMatrix.Data.Database db = new WebMatrix.Data.Database();
            db.Open(ConString);
            Data = db.Query("SELECT * FROM " + table);
        }
        else
        {
            using (OdbcConnection con = ne4w OdbcConnection(ConString))
            {
                OdbcCommand com = new OdbcCommand("Select * From " + table);
                command.CommandType = System.Data.CommandType.Text;
                connection.Open();
                OdbcDataReader reader = command.ExecuteReader();

以下是我通过阅读其他各种帖子尝试过的所有不同的事情:

                // Atempt 1
                Data = reader;
                // Error in view, 'Invalid attempt to call FieldCount when reader is closed' (on 'var row `in` Model.Data')

                // Atempt 2
                Data = reader.Cast<dynamic>;
                // Error: 'Cannot convert method group "Cast" to non-delegate type "dynamic". Did you intend to invoke the method?

                // Atempt 3
                Data = reader.Cast<IEnumerable<dynamic>>;
                // Error same as Atempt 2

                // Atempt 4
                Data = reader.Cast<IEnumerable<string>>;
                // Error same as Atempt 2
            }
        }
    }
}

我正在寻找让读者对象成为IEnumerable&lt;dynamic&gt; 对象的最佳方法。

请注意,这是一个简化的示例,虽然这两种查询类型的原因并不明显,但它们在我的代码中是必需的。

【问题讨论】:

标签: c# webmatrix


【解决方案1】:

您缺少基本的 C# 语法。

Data = reader;
// You cant do this. You have to loop the reader to get the values from it.
// If you simply assign reader object itself as the data you wont be 
// able to get data once the reader or connection is closed. 
// The reader is typically closed in the method.

Data = reader.Cast<dynamic>;
// You should call the Cast method. And preferably execute the resulting query. 
// As of now you're merely assigning method reference to a variable
// which is not what you want. 
// Also bear in mind that, as I said before there's no real benefit in casting to dynamic

Data = reader.Cast<IEnumerable<dynamic>>;
// Cast method itself returns an IEnumerable. 
// You dont have to cast individual rows to IEnumerable

Data = reader.Cast<IEnumerable<string>>;
// Meaningless I believe. 
// The data you get from database is not always strings

你犯的主要错误是没有调用方法。这就是你想要的:

Data = reader.Cast<IDataRecord>().ToList();
                               ^^ // notice the opening and closing parentheses

根据更容易处理的内容(例如,在前端显示),您可以采取多种方式。

  1. 返回数据记录。

    public IEnumerable<IDataRecord> SelectDataRecord()
    {
        ....
    
        using (var reader = cmd.ExecuteReader())
            foreach (IDataRecord record in reader as IEnumerable)
                yield return record; //yield return to keep the reader open
    }
    
  2. 返回 ExpandoObjects。 也许这就是你想要的?

    public IEnumerable<dynamic> SelectDynamic()
    {
        ....
    
        using (var reader = cmd.ExecuteReader())
        {
            var names = Enumerable.Range(0, reader.FieldCount).Select(reader.GetName).ToList();
            foreach (IDataRecord record in reader as IEnumerable)
            {
                var expando = new ExpandoObject() as IDictionary<string, object>;
                foreach (var name in names)
                    expando[name] = record[name];
    
                yield return expando;
            }
        }
    }
    
  3. 属性包的返回顺序

    public IEnumerable<Dictionary<string, object>> SelectDictionary()
    {
        ....
    
        using (var reader = cmd.ExecuteReader())
        {
            var names = Enumerable.Range(0, reader.FieldCount).Select(reader.GetName).ToList();
            foreach (IDataRecord record in reader as IEnumerable)
                yield return names.ToDictionary(n => n, n => record[n]);
        }
    }
    
  4. 普通对象数组的返回序列

    public IEnumerable<List<object>> SelectObjectArray()
    {
        ....
    
        using (var reader = cmd.ExecuteReader())
        {
            var indices = Enumerable.Range(0, reader.FieldCount).ToList();
            foreach (IDataRecord record in reader as IEnumerable)
                yield return indices.Select(i => record[i]).ToList();
        }
    }
    
  5. 返回数据行

    public IEnumerable<DataRow> SelectDataRow()
    {
        ....
    
        using (var reader = cmd.ExecuteReader())
        {
            var table = new DataTable();
            table.BeginLoadData();
            table.Load(reader);
            table.EndLoadData();
            return table.AsEnumerable(); // in assembly: System.Data.DataSetExtensions
        }
    }
    
  6. 最后但同样重要的是,如果有帮助,您可以返回强类型序列,而无需任何手动管道。您可以使用表达式树在运行时编译代码。参见this,例如

【讨论】:

  • 如何创建第二个选项的async 版本?我试过了,一直收到以下错误:The body of DbHelper.GetDataFromSproc(string sprocName, Dictionary&lt;string, object&gt; parameters)' cannot be an iterator block because 'Task&lt;IEnumerable&lt;dynamic&gt;&gt;' is not an iterator interface type
  • @Code 看到这个帖子:stackoverflow.com/questions/23295119/…
  • 这就是答案!这里我充分利用了版本 2 ExpandoObject。感谢分享。 :-)
【解决方案2】:

尝试循环阅读器结果:

OdbcDataReader reader = command.ExecuteReader();

while(reader.Read())
{
    var item = reader["yourField"].ToString();
}

看起来您只是想将一个对象设置为 command.ExecuteReader(); 的未执行 IQueriable 结果。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-16
    • 2017-10-21
    • 2012-02-23
    • 2016-03-27
    • 2015-04-19
    相关资源
    最近更新 更多