感谢@Stinky Buffalo 的回答。
在字典中添加重复键时,我会更改您的代码并解决错误。
示例:
CreateDate%20gt%202021-05-22T00:00:00Z%20and%20CreateDate%20lt%202021-05-26T00:00:00Z%20
还有:
BookRequestType%20eq%20%27BusDomestic%27%20or%20BookRequestType%20eq%20%27TrainDomestic%27%20or%20BookRequestType%20eq%20%27FlightDomestic%27%20
以下代码对我来说效果很好:
首先安装Install-Package Microsoft.Data.OData -Version 5.8.4 包。
然后创建名为“ODataHelper”的类,然后复制以下代码:
public class ODataHelper<T> where T : class
{
private static readonly TextInfo TextInfo = new CultureInfo("en-US", false).TextInfo;
public static Dictionary<string, Tuple<object, ODataOperatorType>> ODataUriParser(
ODataQueryOptions<T> queryOptions)
{
var dictFilters = new Dictionary<string, Tuple<object, ODataOperatorType>>();
TryNodeValue(queryOptions.Filter?.FilterClause?.Expression, dictFilters);
return dictFilters;
}
private static void TryNodeValue(SingleValueNode node,
IDictionary<string, Tuple<object, ODataOperatorType>> dictFilters)
{
if (node is null)
return;
if (node is SingleValueFunctionCallNode valueFunction)
{
ParseSingleFunctionNode(valueFunction,
Enum.Parse<ODataOperatorType>(TextInfo.ToTitleCase(valueFunction.Name)), dictFilters);
}
if (node is BinaryOperatorNode binaryOperatorNode)
{
var left = binaryOperatorNode.Left;
var right = binaryOperatorNode.Right;
if (left is SingleValuePropertyAccessNode leftNodeRight && right is ConstantNode rightNodeRight)
{
ParseSingleValueNode(
leftNodeRight,
rightNodeRight,
Enum.Parse<ODataOperatorType>(binaryOperatorNode.OperatorKind.ToString()),
dictFilters);
}
switch (left)
{
case ConvertNode node1:
{
var convertLeft = node1.Source;
if (convertLeft is SingleValuePropertyAccessNode leftNodeLeft &&
right is ConstantNode rightNodeLeft)
{
ParseSingleValueNode(
leftNodeLeft,
rightNodeLeft,
Enum.Parse<ODataOperatorType>(
binaryOperatorNode.OperatorKind.ToString()),
dictFilters);
}
else
TryNodeValue(node1.Source, dictFilters);
break;
}
case BinaryOperatorNode:
TryNodeValue(left, dictFilters);
break;
case SingleValueFunctionCallNode functionNode:
ParseSingleFunctionNode(functionNode,
Enum.Parse<ODataOperatorType>(TextInfo.ToTitleCase(functionNode.Name)),
dictFilters);
break;
}
switch (right)
{
case BinaryOperatorNode:
TryNodeValue(right, dictFilters);
break;
case ConvertNode convertNode:
TryNodeValue(convertNode.Source, dictFilters);
break;
case SingleValueFunctionCallNode functionNode:
ParseSingleFunctionNode(functionNode,
Enum.Parse<ODataOperatorType>(TextInfo.ToTitleCase(functionNode.Name)),
dictFilters);
break;
}
}
}
private static void ParseSingleValueNode(
SingleValuePropertyAccessNode left,
SingleValueNode right,
ODataOperatorType operatorKind,
IDictionary<string, Tuple<object, ODataOperatorType>> dictFilters)
{
string key = left.Property.Name.Trim();
object value = ((ConstantNode) right).Value;
object specifiedValue = value is ODataEnumValue enumValue ? enumValue.Value : value;
if (operatorKind is ODataOperatorType.LessThan or ODataOperatorType.LessThanOrEqual)
{
dictFilters.TryAdd($"{key}_To", new Tuple<object, ODataOperatorType>(value, operatorKind));
}
else if (dictFilters.TryGetValue(key, out Tuple<object, ODataOperatorType> currentValue))
{
dictFilters[key] = new Tuple<object, ODataOperatorType>(
$"{currentValue.Item1},{specifiedValue}",
operatorKind);
}
else
{
dictFilters.Add(key, new Tuple<object, ODataOperatorType>(specifiedValue, operatorKind));
}
}
private static void ParseSingleFunctionNode(
SingleValueFunctionCallNode node,
ODataOperatorType operatorKind,
IDictionary<string, Tuple<object, ODataOperatorType>> dictFilters)
{
string key = (node.Parameters.First() as SingleValuePropertyAccessNode)?.Property.Name.Trim();
object value = (node.Parameters.Last() as ConstantNode)?.Value;
if (string.IsNullOrEmpty(Convert.ToString(value)?.Trim()))
return;
dictFilters.TryAdd(key, new Tuple<object, ODataOperatorType>(value, operatorKind));
}
}
public enum ODataOperatorType
{
Equal,
NotEqual,
GreaterThan,
GreaterThanOrEqual,
LessThan,
LessThanOrEqual,
Contains
}
对于调用 ODataUriParser 方法,您需要从输入操作中获取值。
从请求 api 中获取 ODataQueryOptions>:
输入端点动作 => ODataQueryOptions<YourObjectModel> options
public Task<IQueryable<YourObject>> Get(ODataQueryOptions<YourObject> options)
{
// call your service class
}
然后在您的服务类中编写以下代码以调用 ODataUriParser 并使用结果运行:
Dictionary<string, Tuple<object, ODataOperatorType>> dictFilters =
ODataHelper<YourObject>.ODataUriParser(options);
ODataUriParser方法使用示例结果:
if (dictFilters.TryGetValue("Email", out Tuple<object, ODataOperatorType> emailValue))
{
bookRequestProfileDto.Email =
Convert.ToDateTime(emailValue.Item1.ToString());
}
例如,我们想使用 Enum 将数字字符串列表转换为文本字符串列表:
BookRequestType 是枚举类。
if (dictFilters.TryGetValue("BookRequestType", out Tuple<object, ODataOperatorType> bookRequestTypeValue))
{
customerTransactionDto.BookRequestType =
Convert.ToString(bookRequestTypeValue.Item1)
.ConvertStringNamesEnumToStringNumbers<BookRequestType>();
}
// Extesion Method
public static string ConvertStringNamesEnumToStringNumbers<T>(this string stringTypes) where T : Enum
{
var separateStringTypes = stringTypes.Split(',');
StringBuilder stringBuilder = new StringBuilder();
foreach (var item in separateStringTypes)
{
stringBuilder.Append((int) Enum.Parse(typeof(T), item)).Append(',');
}
return stringBuilder.ToString().Remove(stringBuilder.Length - 1);
}