Как эффективно обрабатывать динамическое сопоставление моделей в Dapper QueryAsync на основе нескольких флагов?C#

Место общения программистов C#
Ответить Пред. темаСлед. тема
Anonymous
 Как эффективно обрабатывать динамическое сопоставление моделей в Dapper QueryAsync на основе нескольких флагов?

Сообщение Anonymous »

Я работаю над запросом 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?

Подробнее здесь: https://stackoverflow.com/questions/789 ... ased-on-mu
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «C#»