我知道我可以为所有查询设置DbContext的CommandTimeout,如下所示:
public class YourContext : DbContext
{
public YourContext() : base("YourConnectionString")
{
// Get the ObjectContext related to this DbContext
var objectContext = (this as IObjectContextAdapter).ObjectContext;
// Sets the command timeout for all the commands
// to 2 min instead of the default 30 sec
objectContext.CommandTimeout = 120;
}
}
但是,我希望保持默认值30秒,除了一个需要更长时间的方法。
我应该如何更改此单个查询?
我确实尝试过使用:
public void doSomething(){
// The using had another reason, but in this case it also
// automatically disposes of the DbContext
using(IMyDbContext = delegateDbContext()){
((IObjectContextAdapter)usingDb).ObjectContext.CommandTimeout = 120;
... // myQuery
}
}
一切都很完美,直到我使用Mock-DbContext运行我的UnitTest(是的,我确实将我的委托设置为这个Mock-DbContext)。它给了我一个InvalidCastException
:
System.InvalidCastException: Unable to cast object of type
'Castle.Proxies.FakeMyDbContextProxy' to type
'System.Data.Entity.Infrastructure.IObjectContextAdapter'.
答案 0 :(得分:5)
这是因为您依赖于您不应该了解的实施细节(您的IMyDbContext
也实施IObjectContextAdapter
这一事实)。在单元测试中,IMyDbContext
实例实际上是由模拟框架生成的代理,并且不会实现IObjectContextAdapter
。
由于CommandTimeout
对这个假DbContext
没有意义,我建议你只有在演员成功时才尝试施放和设置CommandTimeout
:
var objectContextAdapter = usingDb as IObjectContextAdapter;
if (objectContextAdapter != null)
objectContextAdapter.ObjectContext.CommandTimeout = 120;
这样,CommandTimeout
将在实际执行环境中设置,但不在单元测试中设置(这并不重要,因为模拟实际上并不查询数据库)< / p>
编辑:实际上,更好更清洁的选择是修改IMyDbContext
以揭示设置CommandTimeout
的方法:
interface IMyDbContext
{
...
int CommandTimeout { get; set; }
}
class MyDbContext : IMyDbContext
{
...
public int CommandTimeout
{
get { return ((IObjectContextAdapter)this).ObjectContext.CommandTimeout; }
set { ((IObjectContextAdapter)this).ObjectContext.CommandTimeout = value; }
}
}
现在你可以这样做:
usingDb.CommandTimeout = 120;
不用担心上下文的实际类型。模拟框架只会为此属性生成一个虚拟实现。
答案 1 :(得分:2)
触及为单个语句设置超时的原始问题。直接的方法有时是最好的。假设您已经按照上面的建议公开了CommandTimeout(好主意),那么在您的函数中:
var originalTimeout = _dbContext.CommandTimeout;
_dbContext.CommandTimeout = 120;
// do something relevant
_dbContext.CommandTimeout = originalTimeout;