当我在服务/存储库之间共享同一个实体时,我应该通过ref传递实体DbContext

时间:2014-07-02 15:58:49

标签: c# entity-framework reference repository-pattern dbcontext

我的服务在其构造函数中使用了DbContext,并且我创建了一个包含所有服务的UnitOfWork类,以确保在它们之间使用相同的DbContext。

unitofwork class的样本

   private myEntities myContext

   public UnitOfWork()
    {
        myContext = new myEntities();
    }

    private RequestService requestService;
    public RequestService RequestService
    {
        get
        {
            if (requestService == null)
                requestService = new RequestService(myContext);

            return requestService;
        }

    }

通过使用此unitofwork类,我的服务的所有DbContext现在都是一致的,并且在一个服务中进行的更改将出现在另一个服务中。

但是,如果我需要更改实际的Entity上下文类,则不会在每个服务中保持持久性。

下面我有一个"刷新"重新初始化它的方法(我需要刷新上下文,以便我可以让这个类与一些遗留代码一起工作)。

    public void Refresh()
    {
        myContext = new myEntities();
    }

但是我的服务类DbContext对象没有被ref传递,所以上下文没有设置为我的实体类的新实例,这导致上下文没有被刷新。

所以我认为我可以通过ref传递来解决这个问题,如下所示

服务类示例

    MyEntities myContext;

    public RequestService(ref MyEntities myContext)
    {
        this.myContext = myContext;

    }

但是我看到有人说你不应该通过ref传递上下文类,所以我很好奇,如果有更好的方法,我正在以错误的方式看待这个?

修改

很抱歉,我提出的传递ref的解决方案并没有解决我的问题,但我仍然对如何更新UnitOfWork类的实体上下文感兴趣,例如将其设置为null并使服务类具有该效果。

1 个答案:

答案 0 :(得分:3)

永远不应该通过引用或作为参考来共享DbContext。它不是线程安全的。

http://msdn.microsoft.com/en-us/data/jj729737.aspx

如果您需要一种简单的方法来生成多个DbContext,请使用Parallel Extensions Extras中的ObjectPool。

更新1

@tia在说原始更改时不会更新私有实例是正确的:

class Program
{
    static void Main(string[] args)
    {
        var pool1 = new ObjectPool<IDbConnection>(() => new SqlConnection("Data Source=server1"));
        var service = new Service(ref pool1);
        pool1 = new ObjectPool<IDbConnection>(() => new SqlConnection("Data Source=server2"));
        Console.WriteLine(service.Pool.GetObject().ConnectionString);
    }
}

class Service
{
    private ObjectPool<IDbConnection> connectionPool;

    public Service(ref ObjectPool<IDbConnection> pool) { this.connectionPool = pool; }

    public ObjectPool<IDbConnection> Pool { get { return connectionPool; }  }
}

将打印&#34;数据源=服务器1&#34;,即使它是静态字段。

输入Monostate, a wicked pattern,与Singleton非常相似。

class Program
{
    static void Main(string[] args)
    {
        var mop = new MonoObjectPool();
        mop.Pool = new ObjectPool<IDbConnection>(() => new SqlConnection("Data Source=server1"));
        var service = new Service();
        mop.Pool = new ObjectPool<IDbConnection>(() => new SqlConnection("Data Source=server2"));
        Console.WriteLine(service.Pool.GetObject().ConnectionString);
    }
}

internal class MonoObjectPool
{
    private static ObjectPool<IDbConnection> pool1;

    public ObjectPool<IDbConnection> Pool

    {
        get { return pool1; }
        set { pool1 = value; }
    }
}

class Service
{
    public ObjectPool<IDbConnection> Pool { get { return new MonoObjectPool().Pool; } }
}

我正在摆脱服务的构造函数,因为我总能得到当前的IDbConnection生成器。无论有多少次实例化MonoObjectPool,它总会只有一个实例。

更新2

另一个选项可能是使用Autofac,但我对它不太熟悉,所以我无法举例说明如何在服务实例中解析类型。这是一个简单的例子:

class Program
{

    private static IContainer container { get; set; }

    static void Main(string[] args)
    {
        var builder = new ContainerBuilder();
        builder.RegisterType<DbCtx1>().As<IDbCtx>();
        container = builder.Build();

        using (var scope = container.BeginLifetimeScope())
        {
            var dbctx = scope.Resolve<IDbCtx>();
            Console.WriteLine(dbctx.GetType());
        }

        builder = new ContainerBuilder();
        builder.RegisterType<DbCtx2>().As<IDbCtx>();
        container = builder.Build();

        using (var scope = container.BeginLifetimeScope())
        {
            var dbctx = scope.Resolve<IDbCtx>();
            Console.WriteLine(dbctx.GetType());
        }
    }
}

interface IDbCtx
{

}

class DbCtx1 : IDbCtx { }
class DbCtx2 : IDbCtx { }

更新3

所以回到Monostate,这可以按预期工作:

class Program
{
    static void Main(string[] args)
    {
        var mop = new MonoObjectPool();
        mop.Pool = new ObjectPool<IDbConnection>(() => new SqlConnection("Data Source=server1"));
        var service = new Service(mop);
        mop.Pool = new ObjectPool<IDbConnection>(() => new SqlConnection("Data Source=server2"));
        Console.WriteLine(service.Pool.GetObject().ConnectionString);
    }
}

internal class MonoObjectPool
{
    private static ObjectPool<IDbConnection> pool1;

    public ObjectPool<IDbConnection> Pool
    {
        get { return pool1; }
        set { pool1 = value; }
    }
}

class Service
{
    private MonoObjectPool myPool;
    public Service(MonoObjectPool pool) { myPool = pool; }
    public ObjectPool<IDbConnection> Pool { get { return myPool.Pool; } }
}

我希望这会有所帮助。