关闭数据库连接后使用匿名类型

时间:2011-05-01 17:19:59

标签: c# entity-framework anonymous-types

我的代码类似于以下内容。

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)
    {
        /* ... */
    }
}

这似乎工作正常,但我的循环有很多处理。我担心在处理过程中我会打开数据库连接或其他资源。

我尝试在var activities语句之前声明using,以便我可以在using语句之后处理数据,但是必须在声明它的地方初始化此变量。

了解EF内部工作原理的人是否可以告诉我,当EF上下文“活着”时,是否存在长时间处理的问题,以及我如何减轻这些问题。

虽然我很喜欢,但也许您也可以评论我在循环中使用act.Category.CatName的事实。这是相关表格中的值。我最好在我的EF查询中使用连接,这样我就可以一次性获取数据而不是强制另一个(?)数据库访问来获取相关数据吗?

5 个答案:

答案 0 :(得分:5)

您可以让编译器通过调用泛型方法来推断结果类型:

    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(),否则在您对其进行枚举之前,您的查询将不会被实际执行,这将在上下文关闭后发生。

答案 1 :(得分:2)

您的问题是希望匿名类型可以在其上下文之外访问。您可以为结果使用特定类型,并可以灵活地在任何地方访问值。

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)
{
    /* ... */
}

答案 2 :(得分:1)

将读取和处理分开的最大问题是你的代码完全没有这样做。

第一个语句只创建一个能够获取数据的表达式,但它实际上并不提取任何内容。直到你开始阅读它才能获得任何数据。

在使用该代码处理数据之前,您需要做两件事才能关闭数据库连接。您必须使用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) {
    /* ... */
}

这种方法的一个缺点是你没有得到try...finally提供的代码的隐式using,所以如果在获取数据时出错,则上下文不会处置。

另一种方法是声明一个可以保存您读取的数据的类,以便您可以使用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();
}

答案 3 :(得分:1)

如果我需要长时间使用DB的结果,我通常会创建该特定类型,只需声明一个包含所需字段的类,而不是使用匿名类型,在从数据库获取数据后,我会生成一个线程我做了所需的工作。这样,与数据库的连接就会关闭,应用程序仍然会响应。

答案 4 :(得分:0)

您可以手动处理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