11

我希望能够遍历实体表中的每一行,而无需将每一行都保存在内存中。这是一个只读操作,每一行在处理后都可以丢弃。

如果有办法在处理后丢弃该行,那很好。我知道这可以使用 DataReader 来实现(不在 EF 的范围内),但是可以在 EF 中实现吗?

或者有没有办法在不直接使用 SQL 的情况下从 EF 中获取 DataReader?

更详细的例子:

使用 EF 我可以编码:

foreach (Quote in context.Quotes)
   sw.WriteLine(sw.QuoteId.ToString()+","+sw.Quotation);

但要使用 DataReader 获得相同的结果,我需要编写代码:

// get the connection to the database
SqlConnection connection = context.Database.Connection as SqlConnection;

// open a new connection to the database
connection.Open();

// get a DataReader for our table
SqlCommand command = new SqlCommand(context.Quotes.ToString(), connection);
SqlDataReader dr = command.ExecuteReader();

// get a recipient for our database fields
object[] L = new object[dr.FieldCount];

while (dr.Read())
{
    dr.GetValues(L);
    sw.WriteLine(((int)L[0]).ToString() + "," + (string)L[1]);
}

不同之处在于前者内存不足(因为它正在拉入客户端内存中的整个表),而后者运行完成(并且速度更快),因为它在任何时候只在内存中保留一行。

但同样重要的是,后一个示例失去了 EF 的强类型化,并且如果数据库发生更改,可能会引入错误。

因此,我的问题是:我们能否在 EF 中返回强类型行时得到类似的结果?

4

4 回答 4

5

根据您最后的评论,我仍然感到困惑。看看下面的两个代码。

英孚

using (var ctx = new AppContext())
{
    foreach (var order in ctx.Orders)
    {
        Console.WriteLine(order.Date);
    }
}

EF 探查器

数据阅读器

var constr = ConfigurationManager.ConnectionStrings["AppContext"].ConnectionString;
using (var con = new SqlConnection(constr))
{
    con.Open();    
    var cmd = new SqlCommand("select * from dbo.Orders", con);
    var reader = cmd.ExecuteReader();
    while (reader.Read())
    {
        Console.WriteLine(reader["Date"]);
    }
}

数据读取器分析器

尽管 EF 的初始查询很少,但它们都执行类似的查询,可以从探查器中看到。

于 2014-07-17T06:47:48.267 回答
1

我还没有测试过,但是试试foreach (Quote L in context.Quotes.AsNoTracking()) {...}.AsNoTracking()不应将实体放入缓存中,因此我假设当它们超出范围时它们将被 GC 消耗。

另一种选择是context.Entry(quote).State = EntityState.Detached;在 foreach 循环中使用。应该具有与选项 1 类似的效果。

第三个选项(肯定可以工作,但需要更多编码)是实现批处理(选择前 N 个实体,处理,选择下一个前 N 个)。在这种情况下,请确保您在每次迭代时处理并创建新的上下文(以便 GC 可以吃掉它:))并在查询中使用正确的 OrderBy()。

于 2014-07-17T15:27:46.850 回答
0

您需要使用EntityDataReader,它的行为方式类似于传统的 ADO.NET DataReader

问题是,要这样做,您需要使用ObjectContext而不是DbContext,这使事情变得更加困难。

请参阅这个 SO 答案,而不是公认的答案:How can I return a datareader when using Entity Framework 4?

即使这指的是 EF4,在 EF6 中也以相同的方式工作。通常,ORM 不适合流式传输数据,这就是为什么此功能如此隐藏的原因。

也可以看看这个项目:Entity Framework (Linq to Entities) to IDataReader Adapter

于 2014-07-17T07:51:08.290 回答
0

我已经按页完成了。并在每次页面加载后清理上下文。

示例:加载前 50 行迭代它们清理上下文或创建一个新的。

加载第二个 50 行...

清理上下文 = 将其所有条目设置为已分离。

于 2020-03-07T08:08:49.207 回答