关闭数据库连接后处理匿名类型

本文关键字:类型 后处理 数据库连接 | 更新日期: 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