我希望能够遍历实体表中的每一行而不保留内存中的每一行。这是一个只读操作,每行可以在处理后丢弃。
如果有办法在处理后丢弃该行,那就没问题。我知道这可以使用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中返回强类型行获得类似的结果?
答案 0 :(得分:5)
根据你上次发表的评论,我仍感到困惑。看看以下两个代码。
using (var ctx = new AppContext())
{
foreach (var order in ctx.Orders)
{
Console.WriteLine(order.Date);
}
}
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初始查询很少,它们都执行类似的查询,可以从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行 ...
清除上下文=将其所有条目设置为已分离。