Я работаю над запросом Dapper, который извлекает данные для запроса GraphQL из нескольких связанных таблиц, таких как ImportJob, ImportJobChargeDetail и ImportJobContainerDetail. Данные, которые необходимо получить, зависят от некоторых флагов запроса, таких как IncludeCharge и IncludeContainer. На основе этих флагов мне нужно включить или исключить из запроса определенные связанные модели.
В настоящее время у меня есть несколько блоков if-else для обработки различных комбинаций этих флагов, но этот подход не подходит. не масштабируется, и его становится сложно поддерживать, если в будущем будет добавлено больше флагов или условий.
using Dapper;
using System.Data;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
namespace ECommerce.Application.Queries.Handlers;
internal class GetOrdersByFieldsAndFiltersQueryHandler : IRequestHandler
{
private readonly IDbConnection _db;
public GetOrdersByFieldsAndFiltersQueryHandler(IDbConnection dbConnection)
{
_db = dbConnection;
}
public async Task Handle(GetOrdersByFieldsAndFiltersQuery request, CancellationToken cancellationToken)
{
var directFields = request.Fields?.Where(field => !IsNestedField(field)).ToList();
var nestedFields = request.Fields?.Where(field => IsNestedField(field)).ToList();
if (!directFields.Contains("order_number", StringComparer.OrdinalIgnoreCase))
{
directFields.Add("order_number");
}
// Convert direct field names to snake_case
var fieldSelection = directFields == null || directFields.Count == 0
? "o.*"
: string.Join(", ", directFields.Select(field => $"o.{ToSnakeCase(field.Trim())}"));
string filterCondition = "";
DynamicParameters parameters = new DynamicParameters();
if (request.Filters != null && request.Filters.Any() == true)
{
var filterResult = CreateFilterCondition(request.Filters);
filterCondition = filterResult.SqlWhereClause;
parameters = filterResult.Parameters;
}
var query = new StringBuilder();
query.AppendLine($"SELECT {fieldSelection} ");
if (request.IncludeOrderDetails)
{
query.AppendLine(", od.order_number AS OrderNumber, od.*");
}
if (request.IncludeShippingInfo)
{
query.AppendLine(", sh.order_number AS ShippingOrderNumber, sh.*");
}
query.AppendLine("FROM orders AS o");
if (request.IncludeOrderDetails)
{
query.AppendLine("LEFT JOIN order_details od ON od.order_number = o.order_number");
}
if (request.IncludeShippingInfo)
{
query.AppendLine("LEFT JOIN shipping_info sh ON sh.order_number = o.order_number");
}
if (!string.IsNullOrEmpty(filterCondition))
{
query.AppendLine(filterCondition);
}
string splitOn = "OrderNumber";
if (request.IncludeOrderDetails && request.IncludeShippingInfo)
{
splitOn += ",ShippingOrderNumber";
}
else if (!request.IncludeOrderDetails && request.IncludeShippingInfo)
{
splitOn = "ShippingOrderNumber";
}
var orderDictionary = new Dictionary();
if (request.IncludeOrderDetails && request.IncludeShippingInfo)
{
var queryResult = await _db.QueryAsync(
query.ToString(),
(order, detail, shipping) =>
{
Order currentOrder = order;
if (!orderDictionary.TryGetValue(order.OrderNumber, out currentOrder))
{
currentOrder = order;
orderDictionary.Add(currentOrder.OrderNumber!, currentOrder);
}
if (detail != null)
{
currentOrder.OrderDetails = currentOrder.OrderDetails ?? new List();
currentOrder.OrderDetails.Add(detail);
}
if (shipping != null)
{
currentOrder.ShippingInfo = currentOrder.ShippingInfo ?? new ShippingInfo();
currentOrder.ShippingInfo = shipping;
}
return currentOrder;
},
parameters,
splitOn: splitOn
);
}
else if (!request.IncludeOrderDetails && request.IncludeShippingInfo)
{
var queryResult = await _db.QueryAsync(
query.ToString(),
(order, shipping) =>
{
Order currentOrder = order;
if (!orderDictionary.TryGetValue(order.OrderNumber, out currentOrder))
{
currentOrder = order;
orderDictionary.Add(currentOrder.OrderNumber!, currentOrder);
}
if (shipping != null)
{
currentOrder.ShippingInfo = currentOrder.ShippingInfo ?? new ShippingInfo();
currentOrder.ShippingInfo = shipping;
}
return currentOrder;
},
parameters,
splitOn: splitOn
);
}
else if (request.IncludeOrderDetails && !request.IncludeShippingInfo)
{
var queryResult = await _db.QueryAsync(
query.ToString(),
(order, detail) =>
{
Order currentOrder = order;
if (!orderDictionary.TryGetValue(order.OrderNumber, out currentOrder))
{
currentOrder = order;
orderDictionary.Add(currentOrder.OrderNumber!, currentOrder);
}
if (detail != null)
{
currentOrder.OrderDetails = currentOrder.OrderDetails ?? new List();
currentOrder.OrderDetails.Add(detail);
}
return currentOrder;
},
parameters,
splitOn: splitOn
);
}
else
{
// Query for orders without order details or shipping info
var queryResult = await _db.QueryAsync(
query.ToString(),
parameters
);
foreach (var order in queryResult)
{
if (!orderDictionary.ContainsKey(order.OrderNumber))
{
orderDictionary.Add(order.OrderNumber, order);
}
}
}
return orderDictionary.Values.ToList();
}
private bool IsNestedField(string field)
{
return field.Equals("order_details", StringComparison.OrdinalIgnoreCase) ||
field.Equals("shipping_info", StringComparison.OrdinalIgnoreCase);
}
public static (string SqlWhereClause, DynamicParameters Parameters) CreateFilterCondition(IEnumerable filters)
{
var parameters = new DynamicParameters();
var filterIndex = 0;
var joinedFilters = string.Join(" AND ", filters.Select(filter =>
{
var parts = filter.Split(new[] { '=' }, 2);
if (parts.Length != 2) return filter; // In case of a malformed filter
var column = Regex.Replace(parts[0].Trim(), @"\b[a-z][a-zA-Z]*\b", match =>
{
return ToSnakeCase($"o.{match.Value}");
});
var parameterName = $"@param{filterIndex}";
parameters.Add(parameterName, parts[1].Trim().Trim('\'')); // Add to parameters
filterIndex++;
return $"{column} = {parameterName}";
}));
return ($" WHERE {joinedFilters}", parameters);
}
private static string ToSnakeCase(string input)
{
return Regex.Replace(input, "([a-z])([A-Z])", "$1_$2").ToLower();
}
}
Я ищу более эффективное решение, которое могло бы обрабатывать несколько комбинаций этих флагов без увеличения количества блоков if-else по мере добавления дополнительных условий. Цель состоит в том, чтобы динамически определять, какие модели включать в запрос, и соответствующим образом сопоставлять их.
Какой подход будет более удобным в обслуживании и масштабируемым для обработки этого сценария в Dapper?
Я работаю над запросом Dapper, который извлекает данные для запроса GraphQL из нескольких связанных таблиц, таких как ImportJob, ImportJobChargeDetail и ImportJobContainerDetail. Данные, которые необходимо получить, зависят от некоторых флагов запроса, таких как IncludeCharge и IncludeContainer. На основе этих флагов мне нужно включить или исключить из запроса определенные связанные модели. В настоящее время у меня есть несколько блоков if-else для обработки различных комбинаций этих флагов, но этот подход не подходит. не масштабируется, и его становится сложно поддерживать, если в будущем будет добавлено больше флагов или условий. [code]using Dapper; using System.Data; using System.Text; using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks;
namespace ECommerce.Application.Queries.Handlers;
internal class GetOrdersByFieldsAndFiltersQueryHandler : IRequestHandler { private readonly IDbConnection _db;
public GetOrdersByFieldsAndFiltersQueryHandler(IDbConnection dbConnection) { _db = dbConnection; }
public async Task Handle(GetOrdersByFieldsAndFiltersQuery request, CancellationToken cancellationToken) { var directFields = request.Fields?.Where(field => !IsNestedField(field)).ToList(); var nestedFields = request.Fields?.Where(field => IsNestedField(field)).ToList();
if (!directFields.Contains("order_number", StringComparer.OrdinalIgnoreCase)) { directFields.Add("order_number"); }
// Convert direct field names to snake_case var fieldSelection = directFields == null || directFields.Count == 0 ? "o.*" : string.Join(", ", directFields.Select(field => $"o.{ToSnakeCase(field.Trim())}"));
string filterCondition = "";
DynamicParameters parameters = new DynamicParameters();
if (request.Filters != null && request.Filters.Any() == true) { var filterResult = CreateFilterCondition(request.Filters); filterCondition = filterResult.SqlWhereClause; parameters = filterResult.Parameters; }
var query = new StringBuilder();
query.AppendLine($"SELECT {fieldSelection} ");
if (request.IncludeOrderDetails) { query.AppendLine(", od.order_number AS OrderNumber, od.*"); }
if (request.IncludeShippingInfo) { query.AppendLine(", sh.order_number AS ShippingOrderNumber, sh.*"); }
query.AppendLine("FROM orders AS o");
if (request.IncludeOrderDetails) { query.AppendLine("LEFT JOIN order_details od ON od.order_number = o.order_number"); }
if (request.IncludeShippingInfo) { query.AppendLine("LEFT JOIN shipping_info sh ON sh.order_number = o.order_number"); }
if (!string.IsNullOrEmpty(filterCondition)) { query.AppendLine(filterCondition); }
if (request.IncludeOrderDetails && request.IncludeShippingInfo) { var queryResult = await _db.QueryAsync( query.ToString(), (order, detail, shipping) => { Order currentOrder = order;
if (!orderDictionary.TryGetValue(order.OrderNumber, out currentOrder)) { currentOrder = order; orderDictionary.Add(currentOrder.OrderNumber!, currentOrder); }
if (detail != null) { currentOrder.OrderDetails = currentOrder.OrderDetails ?? new List(); currentOrder.OrderDetails.Add(detail); }
if (shipping != null) { currentOrder.ShippingInfo = currentOrder.ShippingInfo ?? new ShippingInfo(); currentOrder.ShippingInfo = shipping; }
return currentOrder; }, parameters, splitOn: splitOn ); } else if (!request.IncludeOrderDetails && request.IncludeShippingInfo) { var queryResult = await _db.QueryAsync( query.ToString(), (order, shipping) => { Order currentOrder = order;
if (!orderDictionary.TryGetValue(order.OrderNumber, out currentOrder)) { currentOrder = order; orderDictionary.Add(currentOrder.OrderNumber!, currentOrder); }
if (shipping != null) { currentOrder.ShippingInfo = currentOrder.ShippingInfo ?? new ShippingInfo(); currentOrder.ShippingInfo = shipping; }
return currentOrder; }, parameters, splitOn: splitOn ); } else if (request.IncludeOrderDetails && !request.IncludeShippingInfo) { var queryResult = await _db.QueryAsync( query.ToString(), (order, detail) => { Order currentOrder = order;
if (!orderDictionary.TryGetValue(order.OrderNumber, out currentOrder)) { currentOrder = order; orderDictionary.Add(currentOrder.OrderNumber!, currentOrder); }
if (detail != null) { currentOrder.OrderDetails = currentOrder.OrderDetails ?? new List(); currentOrder.OrderDetails.Add(detail); }
return currentOrder; }, parameters, splitOn: splitOn ); } else { // Query for orders without order details or shipping info var queryResult = await _db.QueryAsync( query.ToString(), parameters );
foreach (var order in queryResult) { if (!orderDictionary.ContainsKey(order.OrderNumber)) { orderDictionary.Add(order.OrderNumber, order); } } }
public static (string SqlWhereClause, DynamicParameters Parameters) CreateFilterCondition(IEnumerable filters) { var parameters = new DynamicParameters(); var filterIndex = 0;
var joinedFilters = string.Join(" AND ", filters.Select(filter => { var parts = filter.Split(new[] { '=' }, 2); if (parts.Length != 2) return filter; // In case of a malformed filter
var column = Regex.Replace(parts[0].Trim(), @"\b[a-z][a-zA-Z]*\b", match => { return ToSnakeCase($"o.{match.Value}"); });
var parameterName = $"@param{filterIndex}"; parameters.Add(parameterName, parts[1].Trim().Trim('\'')); // Add to parameters
[/code] Я ищу более эффективное решение, которое могло бы обрабатывать несколько комбинаций этих флагов без увеличения количества блоков if-else по мере добавления дополнительных условий. Цель состоит в том, чтобы динамически определять, какие модели включать в запрос, и соответствующим образом сопоставлять их. Какой подход будет более удобным в обслуживании и масштабируемым для обработки этого сценария в Dapper?
Я работаю над запросом Dapper, который извлекает данные для запроса GraphQL из нескольких связанных таблиц, таких как ImportJob, ImportJobChargeDetail и ImportJobContainerDetail. Данные, которые необходимо получить, зависят от некоторых флагов...
Я конвертирую API Visual Basic в .NET 8, используя тот же запрос SQL с теми же параметрами, и заметил, что одна конкретная строка не отображается в объекте ответа.
В запросе используется UNION ALL, а строка существует только во втором операторе...
Я конвертирую API Visual Basic в .NET 8, используя тот же запрос SQL Server с теми же параметрами, и заметил, что некоторые строки не отображаются в объекте ответа.
В запросе используется UNION ALL, а строки существуют только во втором операторе...
При использовании флагов в Python сопоставление с образцом фиксирует только прямое равенство, а не включение. Однако его можно обойти с помощью условия и in, при условии, что вы перед этим поймаете флаг 0, если считаете, что это особый случай:
from...
Я пытаюсь использовать функцию QueryAsync из AWS C# SDK, вот мой код:
var request = new QueryRequest
{
TableName = happy-projects ,
KeyConditionExpression = PK = :PK and SK = :SK ,
ExpressionAttributeValues = new Dictionary
{
{ :PK , new...