由于DbContext已被丢弃,因此无法完成操作

时间:2012-11-29 02:03:43

标签: c# entity-framework extension-methods

我是EF新手,我正在尝试使用从我的数据库类型User转换为我的信息类UserInfo的扩展方法。
如果这有所作为,我首先使用数据库?

下面的代码给出了错误

  

由于已经处理了DbContext,因此无法完成操作。

try
{
    IQueryable<User> users;
    using (var dataContext = new dataContext())
    {
        users = dataContext.Users
                  .Where(x => x.AccountID == accountId && x.IsAdmin == false);
        if(users.Any() == false)
        {
            return null;
        }
    }
    return users.Select(x => x.ToInfo()).ToList(); // this line is the problem
}
catch (Exception ex)
{
    //...
}

我可以理解为什么会这样做,但我也不明白为什么where语句的结果没有保存到users对象中?

所以我想我的主要问题是为什么它不起作用,其次是什么是使用扩展方法和EF的正确方法?

8 个答案:

答案 0 :(得分:34)

question & answer让我相信IQueryable需要一个活跃的上下文来操作它。这意味着你应该尝试这样做:

try
{
    IQueryable<User> users;

    using (var dataContext = new dataContext())
    {
        users = dataContext.Users.Where(x => x.AccountID == accountId && x.IsAdmin == false);

        if(users.Any() == false)
        {
            return null;
        }
        else
        {
            return users.Select(x => x.ToInfo()).ToList(); // this line is the problem
        }
    }


}
catch (Exception ex)
{
    ...
}

答案 1 :(得分:26)

作为IQueryable<T>IEnumerable<T>公开的对象在迭代或以其他方式访问之前实际上并不“执行”,例如组成List<T>。当EF返回IQueryable<T>时,它基本上只是组成能够检索数据的东西,它实际上并不是在你使用它之前执行检索。

通过在定义IQueryable的位置和调用.ToList()的位置放置断点,可以了解这一点。 (正如Jofry正确指出的那样,来自数据上下文的范围。)在ToList()调用期间完成了提取数据的工作。

因此,您需要将IQueryable<T>保留在数据上下文的范围内。

答案 2 :(得分:13)

您需要记住,在枚举之前,IQueryable查询实际上并未针对数据存储执行。

using (var dataContext = new dataContext())
{

除了构建SQL语句之外,这行代码实际上没有做任何事情

    users = dataContext.Users.Where(x => x.AccountID == accountId && x.IsAdmin == false);

.Any()是一个枚举IQueryable的操作,因此SQL被发送到数据源(通过dataContext),然后对它执行.Any()操作

    if(users.Any() == false)
    {
        return null;
    }
}

你的“问题”行正在重用上面构建的sql,然后执行一个额外的操作(.Select()),它只是添加到查询中。如果你把它留在这里,没有例外,除了你的问题行

return users.Select(x => x.ToInfo()).ToList(); // this line is the problem

调用.ToList(),它枚举IQueryable,这会导致SQL通过原始LINQ查询中使用的dataContext发送到数据源。由于此dataContext已被释放,因此它不再有效,而.ToList()会抛出异常。

这就是“为什么它不起作用”。修复是将这行代码移到dataContext的范围内。

如何正确使用它是另一个问题,一些可以说是正确的答案取决于你的应用程序(Forms vs. ASP.net vs. MVC等)。这实现的模式是工作单元模式。创建新的上下文对象几乎没有任何成本,因此一般规则是创建一个,完成工作,然后处理它。在Web应用程序中,有些人会根据请求创建一个Context。

答案 3 :(得分:3)

抛出错误的原因是对象被处理掉,然后我们尝试通过对象访问表值,但是对象被处理掉了。更好地将它转换为ToList()以便我们可以拥有值

在您使用它之前可能实际上并没有获取数据(它是延迟加载),因此当您尝试执行此工作时,dataContext不存在。我打赌如果你在范围内做了ToList()就可以了。

try
{
    IQueryable<User> users;
    var ret = null;

    using (var dataContext = new dataContext())
    {
        users = dataContext.Users.Where(x => x.AccountID == accountId && x.IsAdmin == false);

        if(users.Any())
        {
            ret = users.Select(x => x.ToInfo()).ToList(); 
        }

     }

   Return ret;
}
catch (Exception ex)
{
    ...
}

答案 4 :(得分:2)

这可以像在存储库中添加ToList()一样简单。例如:

public IEnumerable<MyObject> GetMyObjectsForId(string id)
{
    using (var ctxt = new RcContext())
    {
        // causes an error
        return ctxt.MyObjects.Where(x => x.MyObjects.Id == id);
    }
}

将在调用类中产生Db Context dispos错误,但这可以通过在LINQ操作上添加ToList()显式地执行枚举来解决:

public IEnumerable<MyObject> GetMyObjectsForId(string id)
{
    using (var ctxt = new RcContext())
    {
        return ctxt.MyObjects.Where(x => x.MyObjects.Id == id).ToList();
    }
}

答案 5 :(得分:2)

改变这个:

using (var dataContext = new dataContext())
{
    users = dataContext.Users.Where(x => x.AccountID == accountId && x.IsAdmin == false);

    if(users.Any())
    {
        ret = users.Select(x => x.ToInfo()).ToList(); 
    }

 }

到此:

using (var dataContext = new dataContext())
{
    return = dataContext.Users.Where(x => x.AccountID == accountId && x.IsAdmin == false).Select(x => x.ToInfo()).ToList();
} 

要点是你只想强制一次上下文数据集的枚举。让调用者处理空集场景,就像他们应该的那样。

答案 6 :(得分:2)

在这里,您尝试在非活动DBContext上执行IQueryable对象。你的DBcontext已经被处理掉了。您只能在处理DBContext之前执行IQueryable对象。意味着您需要使用范围

编写users.Select(x => x.ToInfo()).ToList()语句

答案 7 :(得分:0)

using(var database=new DatabaseEntities()){}

不要使用using语句。就这样写

DatabaseEntities database=new DatabaseEntities ();{}

它将起作用。

有关using语句的文档,请参见https://developer.android.com/training/location/change-location-settings