2

我已经开始在一个(有点像 DDD 的)系统中使用 Linq to SQL,它看起来(过于简化)如下所示:

public class SomeEntity // Imagine this is a fully mapped linq2sql class.
{
    public Guid SomeEntityId { get; set; }
    public AnotherEntity Relation { get; set; }
}

public class AnotherEntity // Imagine this is a fully mapped linq2sql class.
{
    public Guid AnotherEntityId { get; set; }
}

public interface IRepository<TId, TEntity>
{
    Entity Get(TId id);
}

public class SomeEntityRepository : IRepository<Guid, SomeEntity>
{
    public SomeEntity Get(Guid id)
    {
        SomeEntity someEntity = null;
        using (DataContext context = new DataContext())
        {
            someEntity = (
                from e in context.SomeEntity
                where e.SomeEntityId == id
                select e).SingleOrDefault<SomeEntity>();
        }

        return someEntity;
    }
}

现在,我遇到了一个问题。当我尝试像这样使用 SomeEntityRepository

public static class Program
{
    public static void Main(string[] args)
    {
        IRepository<Guid, SomeEntity> someEntityRepository = new SomeEntityRepository();
        SomeEntity someEntity = someEntityRepository.Get(new Guid("98011F24-6A3D-4f42-8567-4BEF07117F59"));
        Console.WriteLine(someEntity.SomeEntityId);
        Console.WriteLine(someEntity.Relation.AnotherEntityId);
    }
 }

一切正常,直到程序到达最后一个 WriteLine,因为它抛出一个ObjectDisposedException,因为 DataContext 不再存在。

我确实看到了实际问题,但是我该如何解决呢?我想有几种解决方案,但迄今为止我所想到的没有一个适合我的情况。

  • 摆脱存储库模式,并为工作的每个原子部分使用新的 DataContext。
    • 我真的不想这样做。一个原因是我不想让应用程序知道存储库。另一个是我不认为让 linq2sql 的东西 COM 可见会很好。
    • 另外,我认为这样做context.SubmitChanges()可能会比我预期的要多得多。
  • 指定 DataLoadOptions 以获取相关元素。
    • 因为我希望我的业务逻辑层在某些情况下只回复一些实体,所以我不知道他们需要使用哪些子属性。
  • 禁用所有属性的延迟加载/延迟加载。
    • 不是一个选择,因为有很多表,而且它们的链接很紧密。这可能会导致大量不必要的流量和数据库负载。
  • 互联网上的一些帖子说使用 .Single() 应该会有所帮助。
    • 显然它不...

有什么办法可以解决这个痛苦吗?

顺便说一句:我们决定使用 Linq t0 SQL,因为它是一个相对轻量级的 ORM 解决方案,并且包含在 .NET 框架和 Visual Studio 中。如果 .NET 实体框架更适合这种模式,则可以选择切换到它。(我们在实施方面还没有那么远。)

4

5 回答 5

4

Rick Strahl 在这里有一篇关于 DataContext 生命周期管理的好文章:http ://www.west-wind.com/weblog/posts/246222.aspx 。

基本上,原子操作方法在理论上很好,但您需要保留 DataContext 以便能够跟踪数据对象中的更改(并获取子对象)。

另请参阅: Linq to SQL DataContext和LINQ to SQL的多个/单个实例- 您的 DataContext 位于何处?.

于 2008-11-03T19:10:09.887 回答
1

您必须:

1) 让上下文保持打开状态,因为您还没有完全决定将使用哪些数据(也称为延迟加载)。

或 2) 如果您知道需要其他属性,则在初始加载时提取更多数据。

后者的解释:这里

于 2008-11-03T19:53:16.070 回答
1

如果您使用原子工作单元,我不确定您是否必须放弃存储库。我同时使用这两种方法,尽管我承认放弃了乐观并发检查,因为它们无论如何都不能分层工作(不使用时间戳或其他一些必需的约定)。我最终得到的是一个使用 DataContext 并在完成后将其丢弃的存储库。

这是一个不相关的 Silverlight 示例的一部分,但前三部分显示了我如何使用带有一次性 LINQ to SQL 上下文的存储库模式,FWIW:http ://www.dimebrain.com/2008/09/linq-wcf -silver.html

于 2008-11-03T20:09:43.340 回答
0

指定 DataLoadOptions 以获取相关元素。因为我希望我的业务逻辑层在某些情况下只回复一些实体,所以我不知道他们需要使用哪些子属性。

如果调用者被授予使用 .Relation 属性所需的耦合,那么调用者也可以指定 DataLoadOptions。

DataLoadOptions loadOptions = new DataLoadOptions();
loadOptions.LoadWith<Entity>(e => e.Relation);
SomeEntity someEntity = someEntityRepository
  .Get(new Guid("98011F24-6A3D-4f42-8567-4BEF07117F59"),
  loadOptions);

//

using (DataContext context = new DataContext())
{
  context.LoadOptions = loadOptions;
于 2008-11-03T18:49:28.900 回答
0

这就是我所做的,到目前为止它工作得非常好。

1) 使 DataContext 成为存储库中的成员变量。是的,这意味着您的存储库现在应该实现 IDisposable 并且不要保持打开状态......也许您想避免必须做的事情,但我没有发现它不方便。

2)像这样向您的存储库添加一些方法:

public SomeEntityRepository WithSomethingElseTheCallerMightNeed()
{
 dlo.LoadWith<SomeEntity>(se => se.RelatedEntities);
 return this; //so you can do method chaining
}

然后,你的调用者看起来像这样:

SomeEntity someEntity = someEntityRepository.WithSomethingElseTheCallerMightNeed().Get(new Guid("98011F24-6A3D-4f42-8567-4BEF07117F59"));

您只需要确保当您的存储库访问数据库时,它会使用这些辅助方法中指定的数据加载选项......在我的情况下,“dlo”被保留为成员变量,然后在访问数据库之前进行设置。

于 2009-09-03T23:28:18.503 回答