【问题标题】:Why is my object being disposed?为什么我的对象被处置?
【发布时间】:2018-06-02 14:37:16
【问题描述】:

我正在尝试在 asp.net 框架中使用带有 c# 的 LINQ 访问 SQL 服务器。 我正在网页上写一个简单的登录表单。以下是我的 c# 代码,用于检查它是否在数据库中。

public int getUserId(string un, string pw)
    {
        IEnumerable<int> query;
        using (var context = new IngredientsLinqDataContext())
        {
            query = from c in context.USERs
                        where c.Username == un && c.Password == pw
                        select c.UserID;
        }
        if(query.Count() >= 1)
        {
            return query.Min();//a very serious kludge. Need to fix this
        }
        else { return -1; }

    }
}

检查查询的计数是否大于或等于 1 时会引发对象处置异常。我曾认为,由于查询是在花括号之外声明的,所以这不应该是范围问题。 另外,有什么好的方法可以解决这个问题?它应该只返回一个整数,而不是整数列表。我怎么能这样对待它?谢谢!

【问题讨论】:

  • 您可以选择任何答案并按照他们所说的做...或者您可以扩展您的using 块并在您的Count() 呼叫之后关闭它。会的。
  • 你为什么使用.Count() &gt;= 1?为什么不直接使用.Any(),这样它就不必遍历整个列表来计算是否至少有一项。
  • 附注(但很重要)。在当今时代,您不应该将密码作为纯文本存储在数据库中。即使这只是一个“玩具”示例,实践良好的安全纪律也是一个好主意
  • 另外,我强烈建议只使用Single() 而不是CountMin - 你期望一个结果,所以要求一个。如果它产生多个结果或没有结果,它会抛出一个异常,这就是你应该如何处理这些错误,而不是回到 C 风格的“传回魔法值以指示错误”。

标签: c# sql asp.net linq


【解决方案1】:

改变

query = from c in context.USERs
        where c.Username == un && c.Password == pw
        select c.UserID;

query = (from c in context.USERs
        where c.Username == un && c.Password == pw
        select c.UserID).ToList();

LINQ 使用延迟执行,因此不会立即评估您的查询,而是仅在 query.Count() 进行评估。那个时候的context 已经被处理掉了。这就是您收到错误的原因。

【讨论】:

  • @JudahSchwartz 注意 .ToList(); 会带来所有符合条件的数据。如果你只对计数感兴趣,请query.Count();
【解决方案2】:

context 已被释放,因为您正试图从 context using 块中检索数据库中的数据;

    using (var context = new IngredientsLinqDataContext())
    {
        query = from c in context.USERs
            where c.Username == un && c.Password == pw
            select c.UserID;
        if (query.Count() >= 1)
        {
            return query.Min();//a very serious kludge. Need to fix this
        }
        else { return -1; }
    }

【讨论】:

    【解决方案3】:

    您必须注意,Linq 查询可以是AsEnumerableAsQueryable

    如果您的查询是AsEnumerable,它包含访问查询中的元素所需的所有信息:您可以请求序列中的第一个元素(如果有的话),一旦您有了一个元素,您就可以要求下一个(如果有的话)。如果您的查询在您的流程中使用了其他功能,则它具有访问这些其他功能的所有信息。简而言之:AsEnumerable 在本地内存中处理。

    如果您的查询是AsQueryable,则它包含一个Expression 和一个ProviderProvider 知道指定哪个进程来处理Expression。它知道这个过程使用哪种语言。 Provider 的任务是将Expression 转换为目标处理器的语言并将其发送到此处理器。

    对于实体框架,这通常是 SQL 或 MySQL 等数据库,但也可以是电子表格或 CSV 文件。 DbContext 的好处是您不需要知道它使用哪种语言与其他进程通信。您可以使用相同的 IDbSet 类与完全不同的进程进行通信。

    所以IQueryable 不包含枚举查询中元素的信息。它只知道如何将其翻译成指定进程的语言以及请求谁来执行这个查询。

    在您请求元素之前,翻译和执行不会完成。这意味着您必须保持查询使用的提供对象处于活动状态,直到您不再需要来自该提供对象的任何结果。

    只要你请求一个不使用延迟执行的函数,就会执行查询(如每个 linq 函数的备注部分所述)。这些是 ToList()、FirstOrDefault()、Single()、Count() 等函数。

    WhereSelectGroupBy 等函数以及其他使用延迟执行的函数只会更改 Expression

    结论
    确保您之前已从提供商处获取了所需的所有数据 你 Dispose() 它

    【讨论】:

      【解决方案4】:

      也许这会解决你的问题。

      public int getUserId(string un, string pw)
          {
              int query;
              using (var context = new IngredientsLinqDataContext())
              {
                  --change here
                  query = (from c in context.USERs
                              where c.Username == un && c.Password == pw
                              select c.UserID).FirstOrDefault();
              }
              if(query != 0)       --change here
              {
                  return query;//a very serious kludge. Need to fix this
              }
              else { return -1; }
      
          }
      

      【讨论】:

        【解决方案5】:

        您在此构造中使用query 指示LINQ 在对数据库执行实际查询之前等到对象被访问。在这种情况下,query 是在您的 using 块之外访问的,这就是您收到错误的原因。

        试试这个:

        result = (from c in context.USERs
                  where c.Username == un && c.Password == pw
                  select c.UserID).Min();
        

        【讨论】:

        • 我在这段代码的未来看到了一个异常。以Like this 为例。
        • @john — 我相信你是千里眼 ;-) 感谢您的纠正,我很感激。
        猜你喜欢
        • 1970-01-01
        • 2011-04-17
        • 2017-05-18
        • 1970-01-01
        • 1970-01-01
        • 2011-07-12
        • 1970-01-01
        • 1970-01-01
        • 2020-12-31
        相关资源
        最近更新 更多