要从微风请求中查询信息,请尝试将此作为您的 GET 方法。这假设 GetMyEntityType 在您的数据上下文中返回一个实体。
[HttpGet]
[EnableBreezeQuery(MaxExpansionDepth = 0)]
public QueryResult GetMyEntityType(ODataQueryOptions<MyEntityType> options)
{
... your server method
}
您需要了解的有关微风请求的所有信息都在此对象中。起初我想知道如何在这个对象中包含其他参数,但没有必要 - 参数在对象内部。
要让你的跳过和采取,试试这个......
foreach (var queryParam in options.Request.Properties.FirstOrDefault(x => x.Key == "MS_QueryNameValuePairs").Value as System.Collections.Generic.KeyValuePair<string, string>[])
{
if (queryParam.Key == "$skip")
int.TryParse(queryParam.Value, out skip);
if (queryParam.Key == "$top")
int.TryParse(queryParam.Value, out top);
}
Tips:如果$skip为0,可能不在请求参数中。默认为 0。Breeze 使用 $top,而不是 $take。
您可以使用调用存储过程
DB.ObjectContext.ExecuteStoreQuery<MyEntityType>(query).ToList()
只要查询返回 MyEntityType 类型的实体集,查询就可以是任何东西。EXEC MyStoredProc param1、param2,或者您甚至可以构建动态 SQL。
要返回您自己的 inlineCount,请使用 QueryResult 返回类型:
return new QueryResult()
{
InlineCount = myInlineCount,
Results = DB.ObjectContext.ExecuteStoreQuery<MyEntityType>(query).ToList()
};
提取过滤器并非易事。我找到了一个解决方案并对其进行了修改以添加递归并对其进行调整以处理 Breeze 请求。这些是您需要提取它们的辅助方法和辅助类。
private void ProcessUnaryOperator(UnaryOperatorNode unaryOperator, List<ODataFilter> filterList)
{
if (unaryOperator != null)
{
if (unaryOperator.Operand != null && unaryOperator.Operand.GetType().FullName == "Microsoft.Data.OData.Query.SemanticAst.BinaryOperatorNode")
{
ProcessBinaryOperator(unaryOperator.Operand as BinaryOperatorNode, filterList);
}
}
}
private void ProcessBinaryOperator(BinaryOperatorNode binaryOperator, List<ODataFilter> filterList)
{
if (binaryOperator != null)
{
if (binaryOperator.Left != null && binaryOperator.Left.GetType().FullName == "Microsoft.Data.OData.Query.SemanticAst.BinaryOperatorNode")
ProcessBinaryOperator(binaryOperator.Left as BinaryOperatorNode, filterList);
if (binaryOperator.Right != null && binaryOperator.Right.GetType().FullName == "Microsoft.Data.OData.Query.SemanticAst.BinaryOperatorNode")
ProcessBinaryOperator(binaryOperator.Right as BinaryOperatorNode, filterList);
if (binaryOperator.Left != null && binaryOperator.Left.GetType().FullName == "Microsoft.Data.OData.Query.SingleValueFunctionCallNode")
{
var singleValueFunctionCallNode = binaryOperator.Left as SingleValueFunctionCallNode;
var property = (singleValueFunctionCallNode.Arguments.FirstOrDefault() as SingleValuePropertyAccessNode ?? singleValueFunctionCallNode.Arguments.LastOrDefault() as SingleValuePropertyAccessNode) ;
var constant = (singleValueFunctionCallNode.Arguments.FirstOrDefault() as ConstantNode ?? singleValueFunctionCallNode.Arguments.LastOrDefault() as ConstantNode);
var lt = string.Empty;
switch (singleValueFunctionCallNode.Name)
{
case "startswith":
lt = constant.Value.ToString() + "%";
break;
case "endswith":
lt = "%" + constant.Value.ToString();
break;
case "substringof":
lt = "%" + constant.Value.ToString() + "%";
break;
case "equal":
lt = constant.Value.ToString();
break;
}
if (property != null && property.Property != null && constant != null && constant.Value != null)
filterList.Add(new ODataFilter(property.Property.Name, binaryOperator.OperatorKind.ToString(), lt, property, constant));
}
if (binaryOperator.Left != null && binaryOperator.Left.GetType().FullName == "Microsoft.Data.OData.Query.SingleValuePropertyAccessNode")
{
var property = binaryOperator.Left as SingleValuePropertyAccessNode ?? binaryOperator.Right as SingleValuePropertyAccessNode;
var constant = binaryOperator.Left as ConstantNode ?? binaryOperator.Right as ConstantNode;
var lt = constant.Value.ToString();
if (property != null && property.Property != null && constant != null && constant.Value != null)
filterList.Add(new ODataFilter(property.Property.Name, binaryOperator.OperatorKind.ToString(), lt, property, constant));
}
}
}
public class ODataFilter
{
public ODataFilter(string prop, string op, string lt, SingleValuePropertyAccessNode pn, ConstantNode cn)
{
this.Property = prop;
this.Operator = op;
this.LiteralText = lt;
this.PropertyNode = pn;
this.ConstantNode = cn;
}
public string Property { get; set; }
public string Operator { get; set; }
public string LiteralText { get; set; }
public SingleValuePropertyAccessNode PropertyNode { get; set; }
public ConstantNode ConstantNode { get; set; }
}
这是提取过滤器的调用代码:
List<ODataFilter> filterList = new List<ODataFilter>();
// Not Equal (Unary Operators)
if (options.Filter != null && options.Filter.FilterClause != null && options.Filter.FilterClause.Expression.GetType().Name == "UnaryOperatorNode")
ProcessUnaryOperator(options.Filter.FilterClause.Expression as UnaryOperatorNode, filterList);
// Equal (Binary Operators)
if (options.Filter != null && options.Filter.FilterClause != null && options.Filter.FilterClause.Expression.GetType().Name == "BinaryOperatorNode")
ProcessBinaryOperator(options.Filter.FilterClause.Expression as BinaryOperatorNode, filterList);
这是 USING 的一个子集
using Microsoft.Data.OData.Query;
using System.Web.Http.OData.Query;
using Microsoft.Data.OData.Query.SemanticAst;
您知道您可以执行一个返回多个结果集并使用 MARS 使用这些结果的存储过程吗?我目前运行一个存储过程,它IQueryable
在一次 SQL 往返中返回 23 。
祝你好运!
(编辑)
如果您在存储过程中手动应用 $skip 和 $top,Breeze 将尝试再次将它们应用于结果集。在这种情况下,我只是将 skip 和 top 作为参数发送,而不是使用 $skip 和 $top。顺便说一句,这个 bug 花了 7 个小时才找到。
此链接:https ://www.stevefenton.co.uk/2015/07/getting-the-sql-query-from-an-entity-framework-iqueryable/展示了如何将 IQueryable 对象转换为 T-SQL。使用 options.Filter.ApplyTo 将微风过滤器应用于 MyEntityType 的空白 IQueryable,然后使用上面链接中的代码将微风请求呈现到 TSQL 中。
// Determine the where clause
var whereClause = options.Filter == null ? "" : ToTraceString<MyEntityType>(
options.Filter.ApplyTo(
(from x in DB.Context.MyEntityTypes select x),
new ODataQuerySettings()) as IQueryable<MyEntityType>)
.Split(new[] { "\r", "\n" }, StringSplitOptions.RemoveEmptyEntries).Where(x => x.Trim().StartsWith("WHERE")).FirstOrDefault().Trim();
/* Steve Fenton, https://www.stevefenton.co.uk/2015/07/getting-the-sql-query-from-an-entity-framework-iqueryable/
* July 24, 2015
* */
private static string ToTraceString<T>(IQueryable<T> query)
{
var internalQueryField = query.GetType().GetFields(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).Where(f => f.Name.Equals("_internalQuery")).FirstOrDefault();
var internalQuery = internalQueryField.GetValue(query);
var objectQueryField = internalQuery.GetType().GetFields(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).Where(f => f.Name.Equals("_objectQuery")).FirstOrDefault();
var objectQuery = objectQueryField.GetValue(internalQuery) as System.Data.Entity.Core.Objects.ObjectQuery<T>;
return ToTraceStringWithParameters<T>(objectQuery);
}
private static string ToTraceStringWithParameters<T>(System.Data.Entity.Core.Objects.ObjectQuery<T> query)
{
System.Text.StringBuilder sb = new StringBuilder();
string traceString = query.ToTraceString() + Environment.NewLine;
foreach (var parameter in query.Parameters)
traceString = traceString.Replace("@" + parameter.Name, "'" + parameter.Value.ToString() + "'");
return traceString;
}
/* */