3

I like to wrap my data access in using statements to make myself feel good about garbage collection. I am running Visual Studio 2013 Preview and targeting .NET 4.5. I have an ApiController called WordsController as such:

public class WordsController : ApiController
{
    // GET api/<controller>
    public IEnumerable<Keyword> Get()
    {
        using (TestDataContext dc = new TestDataContext())
        {
            return dc.Keywords;
        }
    }
}

I get an error telling me that the datacontext has been disposed before accessing the data.

Changing the code to this works:

public class WordsController : ApiController
{
    // GET api/<controller>
    public IEnumerable<Keyword> Get()
    {
        TestDataContext dc = new TestDataContext();

        return dc.Keywords;
    }
}

Why does this work when not using the DataContext?

4

4 回答 4

9

return dc.Keywords

实际上并没有在那里执行查询/具体化结果,因此当实际枚举结果时(因此它尝试运行查询),上下文已经被处理。

而是尝试:

using (TestDataContext dc = new TestDataContext())
        {
            return dc.Keywords.ToArray(); // execute the query and materialise NOW
        }

只是在这里添加适当的术语和参考:延迟执行

于 2013-07-25T13:37:49.377 回答
4

AdaTheDev 的回答 是关于为什么它不起作用。您的“使用”语句的范围不包括回报。建议的答案的替代方法是使您的 DbContext 'TestDataContext' 成为 API 控制器中的私有字段,并确保在完成后将其处理掉。其格式如下:

public class WordsController : ApiController
{
     private TestDataContext db = new TestDataContext();

     // GET api/<controller>
     public IEnumerable<Keyword> Get()
     {
         return db.Keywords;
     }

     ... other API methods

    public override void Dispose()
    {
         db.Dispose();
         base.Dispose();
    }
}

这种方法的好处是你可以在同一个 APIController 中反复使用同一个上下文,并且只实例化一次;对于沉重的 DataContext 这可能非常有用。

于 2013-07-25T13:51:33.433 回答
2

用这个:

    public IEnumerable<Keyword> Get()
    {
        List<Keyword> data;
        using (TestDataContext dc = new TestDataContext())
        {
            data = dc.Keywords.ToList();
        } 
        // here you can do some operations with 'data'
        return data;
    }
于 2013-07-25T13:37:11.500 回答
0

我认为您返回的是延迟查询,而不是实际的关键字列表,因此当您的操作返回并且查询实现时,数据上下文已经被处理。

  public class WordsController : ApiController
    {
        // GET api/<controller>
        public IEnumerable<Keyword> Get()
        {
            using (TestDataContext dc = new TestDataContext())
            {
                return dc.Keywords;  //deferred execution
            }

        }
    } //too late to materialize the query.  The context has been disposed

我认为 YD1M 的回答会解决你的问题。一个快速的建议是创建一个简单的服务层并将您的数据访问逻辑放在那里,然后让您的控制器访问该服务,而不是直接访问数据上下文。这不需要解决您的问题,但它会从控制器中删除数据库依赖关系,从而稍微清理您的设计。

于 2013-07-25T16:36:46.653 回答