ブリーズ リクエストから情報を取得するには、これを 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);
}
ヒント: $skip が 0 の場合、リクエスト パラメータに含まれていない可能性があります。デフォルトは 0 です。Breeze は $take ではなく $top を使用します。
を使用してストアド プロシージャを呼び出すことができます。
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
現在、1 回の SQL ラウンド トリップで 23 を返すストアド プロシージャを実行しています。
幸運を!
(編集)
ストアド プロシージャで $skip と $top を手動で適用している場合、Breeze はそれらを結果セットに対して再度適用しようとします。この場合、$skip と $top を使用する代わりに、skip と top をパラメータとして送信しました。ところで、このバグを見つけるのに 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;
}
/* */