关闭数据库连接后处理匿名类型
本文关键字:类型 后处理 数据库连接 | 更新日期: 2023-09-27 17:54:37
我有如下代码:
using (MyEntities context = new MyEntities())
{
var activities = from act in context.Activities
where act.ActTwittered == false
select new { act.ActID, act.ActTitle, act.Category, act.ActDateTime, act.Location };
foreach (var activity in activities)
{
/* ... */
}
}
这似乎工作得很好,但我的循环有很多处理。我担心在这个处理过程中,我留下了一个数据库连接或其他资源打开。
我试着在using
语句之前声明var activities
,这样我就可以在using
语句之后处理数据,但是这个变量必须在声明的地方初始化。
了解EF内部工作原理的人能否告诉我,当EF上下文是"活的"时,是否存在冗长处理的问题,以及我如何缓解这些问题。
当我在这里的时候,也许你也可以评论我在循环中使用act.Category.CatName
的事实。这是一个来自相关表的值。在我的EF查询中使用连接是否更好,以便我一次获得所有数据,而不是强制另一个(?)数据库访问以获得相关数据?
可以让编译器通过调用泛型方法来推断结果类型:
public static T CallFunc<T>( Func<T> theFunc )
{
return theFunc();
}
...
var activities = CallFunc( () =>
{
using( var context = new MyEntities() )
{
return
(
from act in context.Activities
where act.ActTwittered == false
select new { act.ActID, act.ActTitle, act.Category, act.ActDateTime, act.Location };
)
.ToList();
}
} );
foreach( var a in activities ) ...
不要忘记最后的.ToList()
,否则您的查询将不会真正执行,直到您枚举它,这将在上下文关闭后发生。
您的问题是希望匿名类型可以在其上下文中访问。您可以为结果使用特定的类型,并获得在任何地方访问值的灵活性。
public class ActivitySummary
{
public int ActID { get; set; }
public string ActTitle { get; set; }
public string Category { get; set; }
public DateTime ActDateTime { get; set; }
public string Location { get; set; }
}
…
List<ActivitySummary> activities;
using (MyEntities context = new MyEntities())
{
activities = from act in context.Activities
where act.ActTwittered == false
select new ActivitySummary { act.ActID, act.ActTitle, act.Category, act.ActDateTime, act.Location }.ToList();
}
foreach (var activity in activities)
{
/* ... */
}
分离读取和处理的最大问题是,您的代码根本不这样做。
第一条语句只创建了一个能够获取数据的表达式,但实际上它根本没有获取任何东西。直到你开始读取它,它才真正得到任何数据。
在用该代码处理数据之前,您必须做两件事才能关闭数据库连接。通过使用ToList
方法,您必须实际获取数据,而不仅仅是设置表达式,并且您必须使用Dispose
而不是using
,以便您不会将匿名类型隔离在其范围内:
MyEntities context = new MyEntities();
var activities = (
from act in context.Activities
where act.ActTwittered == false
select new { act.ActID, act.ActTitle, act.Category, act.ActDateTime, act.Location }
).ToList();
context.Dispose();
foreach (var activity in activities) {
/* ... */
}
这种方法的一个缺点是,您无法在using
提供的代码周围获得隐式try...finally
,因此,如果在获取数据时出现错误,则不会处理上下文。
另一种选择是声明一个可以保存您读取的数据的类,这样您就可以在using
块之外使用已知的类声明变量:
List<Activity> activities;
using (MyEntities context = new MyEntities()) {
activities = (
from act in context.Activities
where act.ActTwittered == false
select new Activity(act.ActID, act.ActTitle, act.Category, act.ActDateTime, act.Location)
).ToList();
}
在情况下,当我需要与结果从DB工作了很长一段时间,我通常创建特定类型,只是声明一个类与需要的字段,不使用匿名类型,我从数据库获得数据后,我产生一个线程,我做所需的工作。这样,与数据库的连接关闭,应用程序保持响应。
您可以手动处置您的DataContext。
此外,您需要在查询上调用ToArray
,以便它立即执行(而不是在处理上下文之后):
MyEntities context = new MyEntities();
var activities = (from act in context.Activities
where act.ActTwittered == false
select new { act.ActID, act.ActTitle, act.Category, act.ActDateTime, act.Location })
.ToArray();
context.Dispose();
//Do something with activities
但是,我建议切换到非匿名类型,以便您可以继续使用using
来处理上下文。
例如,即使发生异常,using
也会注意调用Dispose
。