我已经开始在一个(类似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不再存在。
我确实看到了实际问题,但我该如何解决?我想有几种解决方案,但到目前为止,我所想到的并不是我的情况。
context.SubmitChanges()
可能会比我想要的更多。有没有办法解决这个痛苦?
BTW:我们决定使用Linq t0 SQL,因为它是一个相对轻量级的ORM解决方案,包含在.NET框架和Visual Studio中。如果.NET实体框架在此模式中更适合,则可以选择切换到它。 (我们在实施方面还没有那么远。)
答案 0 :(得分:4)
Rick Strahl在这里有一篇关于DataContext生命周期管理的好文章:http://www.west-wind.com/weblog/posts/246222.aspx。
基本上,原子动作方法在理论上很不错,但是您需要保留DataContext以便能够跟踪数据对象中的更改(和获取子项)。
另请参阅:Multiple/single instance of Linq to SQL DataContext和LINQ to SQL - where does your DataContext live?。
答案 1 :(得分:1)
答案 2 :(得分:1)
如果你选择原子工作单元,我不确定你是否必须放弃存储库。我同时使用两者,但我承认抛弃乐观并发检查,因为它们无论如何都不能在层中工作(不使用时间戳或其他一些必需的约定)。我最终得到的是一个使用DataContext的存储库,并在完成后将其抛弃。
这是一个不相关的Silverlight示例的一部分,但前三个部分显示了我如何使用具有一次性LINQ to SQL上下文的Repository模式,FWIW:http://www.dimebrain.com/2008/09/linq-wcf-silver.html
答案 3 :(得分: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;
答案 4 :(得分: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”保留为成员变量,然后在命中之前设置db。