2012-09-14 64 views
2

我建立使用实体框架代码首先与mvc4 Web应用程序的方式分层的应用,主要是分离的DataServicesWeb实体框架:Code First。共享和实例上下文

从我的网站我这样做:

public void Foo() { 
    EntityService _svc = new EntityService(); 
    Entity = _svc.FindById(1); 
} 

服务的方法是这样的:

private readonly MyContext _ctx = new MyContext(); 

public Entity FindById(long id) { 
    return _ctx.Entities.SingleOrDefault(q => q.EntityId == id); 
} 

问题是,当我需要使用一个以上的服务,因为每个服务将创建它是自己的上下文。

试图解决这个我做了这样的事情:

public class MyContext : DbContext { 
    private static MyContext _ctx; 

    public MyContext() : base("name=myConnectionString") { } 

    public static MyContext GetSharedInstance() { 
     return GetSharedInstance(false); 
    } 

    public static MyContext GetSharedInstance(bool renew) { 
     if(_ctx == null || renew) 
      _ctx = new MyContext(); 

     return _ctx; 
    } 
} 

改变了我的服务内容如下:

public class EntityService 
{ 
    private readonly MyContext _ctx; 

    public bool SharedContext { get; private set; } 

    public EntityService() 
     : this(false) { } 

    public EntityService(bool sharedContext) 
     : this(sharedContext, false) { } 

    public EntityService(bool sharedContext, bool renew) 
    { 
     SharedContext = sharedContext; 

     if (SharedContext) 
      _ctx = MyContext.GetInstance(renew); 
     else 
      _ctx = new MyContext(); 
    } 
} 

现在,如果我想分享我的上下文的实例,我做这样的事情:

EntityService _entitySvc = new EntityService(true, true); 
AnotherEntityService _anotherEntitySvc = new AnotherEntityService(true); 

这是,至少,这是一个体面的方式来克服呢?我会感谢提供的任何帮助。谢谢。

回答

10

永远不要永远永远永远永远永远永远永远... ...我提到过的?我是认真的。永远不要创建一个静态数据上下文。永远不能。真。我能再强调一下吗?决不。甚至不要去想它。思考它会给你脑癌。

这是在依赖注入真正的亮点的情况之一。通过依赖注入,您可以管理数据上下文的生命周期,并使它们在请求的整个生命周期内运行,而不是应用程序池的生命周期,如静态一样。

详细说明共享上下文为什么不好。不仅上下文在你的类中共享,而且在线程和请求之间共享。这意味着同时使用该网站的两个用户会在所有其他数据上下文中跺脚,导致各种问题。数据上下文不是线程安全的,它们并不安全。

如果你想分享与多个对象的数据上下文,那么你需要将它传递给这些对象,无论是作为一个方法调用的一部分,或作为一个构造函数参数。

我强烈建议通过依赖注入这样做,但是。

+0

+1为DI提,每个请求是要走的路。 – Maess

+0

好的,点了。你能否给我提供一些关于如何通过DI实现这一点的指导,也许我可以用一个简短的例子来改变我的解决方案?谢谢。 – Esteban

+0

@Esteban - 不幸的是,有很多不同种类的依赖注入容器,在你到达那里之前,你需要更多地了解DI。所以很难举一个例子,因为你选择哪个DI容器会影响事物。 –

1

我偶然在此寻找别的东西,而且我最近建立了实体框架的存储库模式。它旨在封装框架,同时让自己的存储库模式发光。你会想要遵循Mystere Man的建议。以下是我建议你接近它的一个粗略示例。

public class MyContext: DbContext, IUnitOfWork 
{ 
    public IDbSet<Note> Notes { get; set; } 
    public IDbSet<DomainType> DomainTypes { get; set; } 
    public IDbSet<DomainValue> DomainValues { get; set; } 
    public IDbSet<Party> Parties { get; set; } 

    public MyContext() :base() 
    { 
     Configuration.LazyLoadingEnabled = false; 
     Configuration.ProxyCreationEnabled = false; 
    } 
} 

正如你所看到的,是的DbContext的IUnitOfWork,它只是有它SaveChanges方法。这是你传入你的仓库的内容。

public abstract class BaseEfRepository<T, TU> : IRepository<T> 
    where T : class 
    where TU : IUnitOfWork 
{ 
    ... 
    virtual public T GetSingle(Expression<Func<T, bool>> whereCondition) 
    { 
     Log.DebugFormat("Called GetSingle<{0}>()...", typeof(T)); 
     return MyEntitySet.Where(whereCondition).FirstOrDefault(); 
    } [etc...] 

} 

这将有大部分的基本的仓库风格的收集访问者和你想要什么封装的。UnitOfWork被传入存储库,因此您可以在同一个事务中拥有任意数量的存储库。

public class NoteRepository: BaseEfRepository<Note, MyContext> 
{ 
    public NoteRepository(MyContext uow) : base(uow) 
    { 
     MyEntitySet = uow.Notes; 
    } 
    public Note GetSingleWithParties(Expression<Func<Note, bool>> whereCondition) 
    { 
     return [... whatever ...] 
    } 

} 

我希望这证明有用。

相关问题