实体框架6:有没有办法在不保存内存中的每一行的情况下迭代表

时间:2014-07-17 05:18:28

标签: entity-framework entity-framework-6 entity-framework-6.1

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

如果有办法在处理后丢弃该行,那就没问题。我知道这可以使用DataReader(超出EF的范围)来实现,但它可以在EF中实现吗?

或者有没有办法从EF中获取DataReader而不直接使用SQL?

更详细的例子:

使用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 个答案:

答案 0 :(得分:5)

根据你上次发表的评论,我仍感到困惑。看看以下两个代码。

EF

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

EF Profiler

数据读取器

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

Data Reader Profiler

即使EF初始查询很少,它们都执行类似的查询,可以从profiler中看到。

答案 1 :(得分:1)

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

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

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

答案 2 :(得分: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

答案 3 :(得分:0)

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

样本: 加载前50行 遍历他们 清理上下文或创建一个新的上下文。

加载第二50行 ...

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