8

更新- 答案显然是 DbLinq 没有Dispose()正确实现。哦!


以下是各种误导 - 底线:DbLinq 不(尚未)等同于 LinqToSql,正如我最初问这个问题时所假设的那样。谨慎使用!

我将存储库模式与 DbLinq 一起使用。我的存储库对象实现了,IDisposable并且该Dispose()方法只做一些事情——调用Dispose(). DataContext每当我使用存储库时,我都会将其包装在一个using块中,如下所示:

public IEnumerable<Person> SelectPersons()
{
    using (var repository = _repositorySource.GetPersonRepository())
    {
        return repository.GetAll(); // returns DataContext.Person as an IQueryable<Person>
    }
}

这个方法返回一个IEnumerable<Person>,所以如果我的理解是正确的,那么在Enumerable<Person>遍历之前实际上不会对数据库进行查询(例如,通过将其转换为列表或数组或在循环中使用它foreach),如下例所示:

var persons = gateway.SelectPersons();
// Dispose() is fired here
var personViewModels = (
    from b in persons
    select new PersonViewModel
    {
        Id = b.Id,
        Name = b.Name,
        Age = b.Age,
        OrdersCount = b.Order.Count()
    }).ToList(); // executes queries

在这个例子中,Dispose()在设置之后立即被调用persons,这是一个IEnumerable<Person>,这是唯一一次被调用。

所以,三个问题:

  1. 这是如何运作的?已处置后,处置后仍如何DataContext查询数据库以获取结果?DataContext
  2. 实际上是做什么的Dispose()
  3. 我听说没有必要(例如,请参阅此问题)处置 a DataContext,但我的印象是这不是一个坏主意。有什么理由处理 DbLinqDataContext吗?
4

3 回答 3

3

1 这是如何工作的?已处置的 DataContext 如何在处置 DataContext 后仍向数据库查询结果?

不起作用。有些东西你没有给我们看。我猜你的存储库类没有正确/在正确的时间处理,或者你在每个查询结束时DataContext都敷衍了事,这完全否定了你通常得到的查询转换和延迟执行。ToList()

在测试应用程序中尝试以下代码,我保证它会抛出ObjectDisposedException

// Bad code; do not use, will throw exception.
IEnumerable<Person> people;
using (var context = new TestDataContext())
{
    people = context.Person;
}
foreach (Person p in people)
{
    Console.WriteLine(p.ID);
}

这是最简单的可重现情况,它总是会抛出。另一方面,如果您people = context.Person.ToList()改为编写,则查询结果已经在块using枚举,我敢打赌,这就是您的情况。

2 Dispose() 实际上做了什么?

除其他外,它设置了一个标志,指示DataContext已处置,在每个后续查询中都会检查该标志,并导致DataContext抛出ObjectDisposedException带有消息的Object name: 'DataContext accessed after Dispose.'.

DataContext如果打开连接并保持打开状态,它也会关闭连接。

3 我听说没有必要(例如,请参阅此问题)处置 DataContext,但我的印象是这不是一个坏主意。有什么理由不处理 LinqToSql DataContext?

必要DisposeDataContext,因为它是必要DisposeIDisposable。如果您未能处置DataContext. 如果从 中检索到的任何实体DataContext保持活动状态,您也可能会泄漏内存,因为上下文为其实现的工作单元模式维护了一个内部身份缓存。但即使不是这种情况,您也不关心Dispose方法在内部做什么。假设它做了一些重要的事情。

IDisposable是一份合同,上面写着“清理可能不是自动的;你需要在完成后处理我。” 您无法保证对象是否有自己的终结器,如果您忘记了,它会在您之后清理Dispose。实现可能会发生变化,这就是为什么依赖观察到的行为而不是显式规范不是一个好主意的原因。

IDisposable如果您使用空Dispose方法处理 an,可能发生的最糟糕的事情是您浪费了一些 CPU 周期。如果您未能IDisposable通过非平凡的实现来处理一个可能发生的最糟糕的事情,那就是您泄漏了资源。这里的选择是显而易见的;如果你看到一个IDisposable,不要忘记处理它。

于 2010-05-17T19:58:08.017 回答
0

“persons”是一个 IEnumerable 集合,DataContext(存储库)只需要进行 .GetNew 调用。

from/select/etc 关键字是添加到 System.Linq 命名空间中的扩展方法的语法糖。这些扩展方法添加了您在查询中使用的 IEnumerable 功能,而不是 DataContext。事实上,您完全可以在不使用 LINQ2SQL 的情况下完成所有这些操作,只需以编程方式创建一个 IEnumerable 来进行演示。

如果您尝试使用这些对象进行任何进一步的存储库 (DataContext) 调用,那么您将收到错误消息。

IEnumerable 集合将包含存储库中的所有记录,这就是您不需要 DataContext 进行查询的原因。

扩展方法:http: //msdn.microsoft.com/en-us/library/bb383977.aspx

LINQ 扩展方法:http: //msdn.microsoft.com/en-us/library/system.linq.enumerable_members.aspx

于 2010-05-17T18:49:48.657 回答
0

在 API 的深处,您可能会看到一个使用如下 API 的方法:

http://msdn.microsoft.com/en-us/library/y6wy5a0f(v=VS.100).aspx

执行命令时,关闭关联的 DataReader 对象时,关闭关联的 Connection 对象。

于 2010-05-17T19:01:00.157 回答