使用实体框架返回数据表

本文关键字:返回 数据表 框架 实体 | 更新日期: 2023-09-27 18:03:36

我使用实体框架。在我的应用程序中有一种特殊情况,我必须使用存储过程。因为有很多SQL语句写在SP中,我不想在我的c#代码中重写它。我只需要以数据表的形式获得结果。我写了一点代码,但我在一个点上卡住了。有人能完成下面的代码吗?

using (dbContext.Database.Connection)
{
dbContext.Database.Connection.Open();
DbCommand cmdItems= dbContext.Database.Connection.CreateCommand();
cmdItems.CommandText = "GetAvailableItems";
cmdItems.CommandType = CommandType.StoredProcedure;
cmdItems.Parameters.Add(new SqlParameter("jobCardId", 100525));
//Need to write code below to populate a DataTable.
}

使用实体框架返回数据表

谢谢大家。我解出来了。解决方案如下:

using (var context = new DataBaseContext())
{
    var dt = new DataTable();
    var conn = context.Database.Connection;
    var connectionState = conn.State;
    try
    {
        if (connectionState != ConnectionState.Open) conn.Open();
        using (var cmd = conn.CreateCommand())
        {
            cmd.CommandText = "GetAvailableItems";
            cmd.CommandType = CommandType.StoredProcedure;
            cmd.Parameters.Add(new SqlParameter("jobCardId", 100525));
            using (var reader = cmd.ExecuteReader())
            {
                dt.Load(reader);
            }
        }
    }
    catch (Exception ex)
    {
        // error handling
        throw;
    }
    finally
    {
        if (connectionState != ConnectionState.Closed) conn.Close();
    }
    return dt;
}

这个例子将返回一个从EntityFramework中选择数据的datatable对象。

我相信这是实现目标的最佳解决方案。然而,这种解决方案的问题是每个记录都是枚举的。您可能希望首先过滤列表,然后从列表中运行这个以避免这种情况。

DataTable dt = new DataTable();
(from rec in database.Table.AsEnumerable()
                     select new
                     {
                         id = rec.id,
                         name = rec.Name
                         //etc
                     }).Aggregate(table, (dt, r) =>
                     {
                         dt.Rows.Add(r.id, r.Name);
                         return dt;
                     });

此解决方案简单,非常快速且易于使用。

创建DbContext扩展:

using System.Data;
using System.Data.Common;
using System.Data.Entity;
..
..
public static class DbContextExtensions
{
    public static DataTable DataTable(this DbContext context, string sqlQuery)
    {
        DbProviderFactory dbFactory = DbProviderFactories.GetFactory(context.Database.Connection);
        using (var cmd = dbFactory.CreateCommand())
        {
            cmd.Connection = context.Database.Connection;
            cmd.CommandType = CommandType.Text;
            cmd.CommandText = sqlQuery;
            using (DbDataAdapter adapter = dbFactory.CreateDataAdapter())
            {
                adapter.SelectCommand = cmd;
                DataTable dt = new DataTable();
                adapter.Fill(dt);
                return dt;
            }
        }
    }
}

例子:

using (MyDbContext db = new MyDbContext())
{
    string query = db.Students.Where(o => o.Age > 20).ToString();
    DataTable dataTable = db.DataTable(query);
    ..
    DataTable dt = db.DataTable(
                         (  from o in db.Studets
                            where o.Age > 20
                            select o
                         ).ToString()
                    );
}

只是改进了以前的解决方案,现在包括通用参数(不是SQL Server特定的)和多个结果集支持:

    DataSet GetDataSet(string sql, CommandType commandType, Dictionary<string, Object> parameters)
    {
        // creates resulting dataset
        var result = new DataSet();
        // creates a data access context (DbContext descendant)
        using (var context = new MyDbContext())
        {
            // creates a Command 
            var cmd = context.Database.Connection.CreateCommand();
            cmd.CommandType = commandType;
            cmd.CommandText = sql;
            // adds all parameters
            foreach (var pr in parameters)
            {
                var p = cmd.CreateParameter();
                p.ParameterName = pr.Key;
                p.Value = pr.Value;
                cmd.Parameters.Add(p);
            }
            try
            {
                // executes
                context.Database.Connection.Open();
                var reader = cmd.ExecuteReader();
                // loop through all resultsets (considering that it's possible to have more than one)
                do
                {
                    // loads the DataTable (schema will be fetch automatically)
                    var tb = new DataTable();
                    tb.Load(reader);
                    result.Tables.Add(tb);
                } while (!reader.IsClosed);
            }
            finally
            {
                // closes the connection
                context.Database.Connection.Close();
            }
        }
        // returns the DataSet
        return result;
    }

我在DataContext类中添加了以下方法:

public async Task<DataTable> ExecReturnQuery(string query)
    {
        using (var command = this.Database.GetDbConnection().CreateCommand())
        {
            command.CommandText = query;
            this.Database.OpenConnection();
            using (var result = await command.ExecuteReaderAsync())
            {
                var table = new DataTable();
                table.Load(result);
                // returning DataTable (instead of DbDataReader), cause can't use DbDataReader after CloseConnection().
                this.Database.CloseConnection();
                return table;
            }
        }
    }

然后我从任何类(我注入DataContext类)调用它,像这样:

DataTable myTableRecords = await _dataContext.ExecReturnQuery("SELECT * FROM MyTable");

我只是把答案混在一起。这段代码运行一个动态查询并将结果转换为字典列表。

public List < Dictionary < string,object >> DataTableToDictionaryList(DataTable table) {
    List < Dictionary < string,
    object >> parentRow = new List < Dictionary < string,
    object >> ();
    Dictionary < string,
    object > childRow;
    foreach(DataRow row in table.Rows) {
        childRow = new Dictionary < string,
        object > ();
        foreach(DataColumn col in table.Columns) {
            childRow.Add(col.ColumnName, row[col]);
        }
        parentRow.Add(childRow);
    }
    return (parentRow);
}
List < Dictionary < string,object >> RunDynamicQuery(string sql, Dictionary < string, Object > parameters = null, int resultSet = 0, CommandType commandType = CommandType.Text) {
    // creates resulting dataset
    var resultDataSet = new DataSet();
    // creates a data access context (DbContext descendant)
    using(var context = new DataDbContext()) {
        // creates a Command 
        var conn = context.Database.Connection;
        var cmd = conn.CreateCommand();
        cmd.CommandType = commandType;
        cmd.CommandText = sql;
        if (parameters != null) {
            // adds all parameters
            foreach(var pr in parameters) {
                var p = cmd.CreateParameter();
                p.ParameterName = pr.Key;
                p.Value = pr.Value;
                cmd.Parameters.Add(p);
            }
        }
        try {
            // executes
            if (conn.State != ConnectionState.Open) {
                conn.Open();
            }
            var reader = cmd.ExecuteReader();
            // loop through all resultsets (considering that it's possible to have more than one)
            int currentResultSet = -1;
            do {
                currentResultSet++;
                //skip lower resultsets
                if (resultSet > currentResultSet) {
                    continue;
                }
                // loads the DataTable (schema will be fetch automatically)
                var tb = new DataTable();
                tb.Load(reader);
                resultDataSet.Tables.Add(tb);
                //make sure to get only one result set
                break;
            } while (! reader . IsClosed );
        }
        finally {
            // closes the connection
            context.Database.Connection.Close();
        }
    }
    return DataTableToDictionaryList(resultDataSet.Tables[0]);
}