我的服务在其构造函数中使用了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并使服务类具有该效果。
答案 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; } }
}
我希望这会有所帮助。