Entity Framework 多个结果集、Azure 连接弹性和命令拦截
Entity Framework Multiple Result Sets, Azure Connection Resiliency and Command Interception
我正在尝试将连接弹性添加到我的存储库 class 并对其进行测试,以便将我的 WCF 服务移动到 Azure。朱莉勒曼有一个很棒的post:
当我调用使用普通 Entity Framework 查询的存储库方法时,会触发 Interceptor ReaderExecuting 方法,我能够模拟连接问题。
var states = dbContext.Blogs.ToList();
但是由于某种原因,当我的其中一个使用从存储过程返回的“多个结果集”的存储库方法正在执行时,不会调用 Interceptor ReaderExecuting 方法(请参见下面的代码)。我期待在执行 "ObjectContext.Translate" 或 "ToList" 时调用 ReaderExecuting 方法,但它不会:
db.Database.Connection.Open();
var reader = cmd.ExecuteReader();
var blogs = ((IObjectContextAdapter)db).ObjectContext.Translate<Blog>(reader).ToList();
仅供参考,我正在关注这篇处理“多个结果集”的文章:
https://msdn.microsoft.com/en-us/data/jj691402.aspx
我正在尝试依靠 Entity Framework 6+ 执行策略来处理连接弹性。但是如果它不能处理多个结果集,我的下一个选择是使用 Polly 库来处理瞬态异常。
你曾经运行遇到过这种情况吗?
你有什么解决办法吗?
您是否尝试过像这样从自定义 DbConfiguration
实现中连接内置连接弹性?
public class MyDbConfiguration : DbConfiguration
{
public MyDbConfiguration()
: base()
{
var strategy = System.Data.Entity.SqlServer.SqlAzureExecutionStrategy();
SetExecutionStrategy("System.Data.EntityClient", strategy);
SetExecutionStrategy("System.Data.SqlClient", strategy);
}
}
我在 MARS 中使用了这种方法,没有遇到任何问题。
在这种情况下,对 ExecuteReader 的调用超出了 EF 的范围 - 代码直接在 ADO.NET 命令对象上调用它。因为您完全绕过 EF 来执行命令,所以您会错过所有 EF(包括拦截器)。翻译只是获取已经检索到的结果并将它们填充到对象中。
由于@tdykstra 提到的 EF 限制,我将存储过程更改为 return 和 XML 输出而不是 "Multiple Result Sets"。我使用 "SqlQuery" 方法调用存储过程并获得输出 XML,然后我将 XML 反序列化为对象。这样 Interceptor ReaderExecuting 方法得到执行,我能够测试连接弹性。希望 EF 团队在未来的版本中添加对 "Multiple Result Sets" 的更多支持。
这是示例代码:
var paramId = new SqlParameter
{
ParameterName = "id",
SqlDbType = SqlDbType.Xml,
Direction = ParameterDirection.Input,
Value = 1
};
var paramXmlResult = new SqlParameter
{
ParameterName = "XmlResult",
SqlDbType = SqlDbType.Xml,
Direction = ParameterDirection.Output
};
db.Database.SqlQuery<XElement>(
"EXEC [dbo].[GetDataAsXml] @id, @XmlResult OUT",
paramId, paramXmlResult).ToList();
XElement xmlResult = XElement.Parse(paramXmlResult.Value.ToString());
//FromXElement is an Extension method that deserializes XML into a Type (like MyData)
MyData data = xmlResult.FromXElement<MyData>();
我正在尝试将连接弹性添加到我的存储库 class 并对其进行测试,以便将我的 WCF 服务移动到 Azure。朱莉勒曼有一个很棒的post:
当我调用使用普通 Entity Framework 查询的存储库方法时,会触发 Interceptor ReaderExecuting 方法,我能够模拟连接问题。
var states = dbContext.Blogs.ToList();
但是由于某种原因,当我的其中一个使用从存储过程返回的“多个结果集”的存储库方法正在执行时,不会调用 Interceptor ReaderExecuting 方法(请参见下面的代码)。我期待在执行 "ObjectContext.Translate" 或 "ToList" 时调用 ReaderExecuting 方法,但它不会:
db.Database.Connection.Open();
var reader = cmd.ExecuteReader();
var blogs = ((IObjectContextAdapter)db).ObjectContext.Translate<Blog>(reader).ToList();
仅供参考,我正在关注这篇处理“多个结果集”的文章:
https://msdn.microsoft.com/en-us/data/jj691402.aspx
我正在尝试依靠 Entity Framework 6+ 执行策略来处理连接弹性。但是如果它不能处理多个结果集,我的下一个选择是使用 Polly 库来处理瞬态异常。
你曾经运行遇到过这种情况吗?
你有什么解决办法吗?
您是否尝试过像这样从自定义 DbConfiguration
实现中连接内置连接弹性?
public class MyDbConfiguration : DbConfiguration
{
public MyDbConfiguration()
: base()
{
var strategy = System.Data.Entity.SqlServer.SqlAzureExecutionStrategy();
SetExecutionStrategy("System.Data.EntityClient", strategy);
SetExecutionStrategy("System.Data.SqlClient", strategy);
}
}
我在 MARS 中使用了这种方法,没有遇到任何问题。
在这种情况下,对 ExecuteReader 的调用超出了 EF 的范围 - 代码直接在 ADO.NET 命令对象上调用它。因为您完全绕过 EF 来执行命令,所以您会错过所有 EF(包括拦截器)。翻译只是获取已经检索到的结果并将它们填充到对象中。
由于@tdykstra 提到的 EF 限制,我将存储过程更改为 return 和 XML 输出而不是 "Multiple Result Sets"。我使用 "SqlQuery" 方法调用存储过程并获得输出 XML,然后我将 XML 反序列化为对象。这样 Interceptor ReaderExecuting 方法得到执行,我能够测试连接弹性。希望 EF 团队在未来的版本中添加对 "Multiple Result Sets" 的更多支持。 这是示例代码:
var paramId = new SqlParameter
{
ParameterName = "id",
SqlDbType = SqlDbType.Xml,
Direction = ParameterDirection.Input,
Value = 1
};
var paramXmlResult = new SqlParameter
{
ParameterName = "XmlResult",
SqlDbType = SqlDbType.Xml,
Direction = ParameterDirection.Output
};
db.Database.SqlQuery<XElement>(
"EXEC [dbo].[GetDataAsXml] @id, @XmlResult OUT",
paramId, paramXmlResult).ToList();
XElement xmlResult = XElement.Parse(paramXmlResult.Value.ToString());
//FromXElement is an Extension method that deserializes XML into a Type (like MyData)
MyData data = xmlResult.FromXElement<MyData>();