Dapper неправильно картирует 1-ко многим сущностямC#

Место общения программистов C#
Ответить Пред. темаСлед. тема
Anonymous
 Dapper неправильно картирует 1-ко многим сущностям

Сообщение Anonymous »

Я динамически получаю вложенные сущности 1 к многим. Dapper не является правильным картированием вложенных сущностей от 1 до многих. В функции карты OBJS имеет 2 элемента. objs [0] - родитель. Родительская организация хороша с действительным значением идентификатора, но в коллекции детей есть 0 пунктов. objs [1] - тип дочернего элемента, но он имеет нулевые значения и id = 0.
Сгенерированный запрос из приведенного ниже кода в порядке, я могу успешно запустить его в Pgadmin, он возвращает 2 ряда, но Dapper не заполняет OBJS [0] с детьми в родительском объекте. И objs [1] - это объект типа дочернего типа, который имеет все нулевое и идентификатор 0.

Код: Выделить всё

 public async Task GetByIdAsync(DynamicGetByIdRequest getByIdReq, CancellationToken cancellationToken = default)
{
Type rootType = ResolveEntityType(getByIdReq.DynamicGetParameter!.EntityName);
var sqlMeta = _metaExtractor.Extract(rootType);

var queryParts = BuildQuery(getByIdReq.DynamicGetParameter, sqlMeta, rootType, "T0");

string sql = $@"SELECT {queryParts.SelectClause}
FROM {sqlMeta.Table.Quote()} AS {"T0".Quote()}
{queryParts.JoinClause}
WHERE {"T0".Quote()}.{"Id".Quote()} = @id";

var lookup = new Dictionary();

await _db.QueryAsync(
sql,
types: queryParts.Types.ToArray(),
map: (object[] objs) =>
{
var root = objs[0];
var rootId = (int)root.GetType().GetProperty("Id").GetValue(root);

if (!lookup.TryGetValue(rootId, out object existing))
{
lookup.Add(rootId, root);
existing = root;

// Initialize collection properties
foreach (var prop in root.GetType().GetProperties())
{
if (prop.PropertyType.IsGenericType &&
prop.PropertyType.GetGenericTypeDefinition() == typeof(List))
{
prop.SetValue(existing, Activator.CreateInstance(prop.PropertyType));
}
}
}

// Handle child objects
for (int i = 1; i < objs.Length; i++)
{
var child = objs[i];

if (child == null)
continue;

var childType = queryParts.Types[i];
var navProp = rootType.GetProperties()
.FirstOrDefault(p => p.PropertyType.IsGenericType &&
p.PropertyType.GetGenericTypeDefinition() == typeof(List) &&
p.PropertyType.GetGenericArguments()[0] == childType);

if (navProp != null)
{
var collection = navProp.GetValue(existing) as IList;
var childId = (int)child.GetType().GetProperty("Id").GetValue(child);

if (!collection.Cast().Any(x =>
(int)x.GetType().GetProperty("Id").GetValue(x) == childId))
{
collection.Add(child);
}
}
}

return existing;
},

param: new { id = getByIdReq.Id },
splitOn: string.Join(",", queryParts.SplitOnColumns)
);

return lookup.Values.FirstOrDefault();
}

private (List Types, string SelectClause, string JoinClause, List SplitOnColumns)
BuildQuery(DynamicGetParameter param, SqlMeta meta, Type entityType, string alias, string? parentAlias = null)
{
var types = new List { entityType };
var selectParts = new List();
var joinParts = new List();
var splitOnColumns = new List();

// 1.  Select all scalar properties for root entity
foreach (var prop in meta.ScalarProps)
{
if (param.Properties == null || param.Properties.Contains(prop.Name, StringComparer.OrdinalIgnoreCase))
{
selectParts.Add($"{alias.Quote()}.{prop.Name.Quote()} AS \"{prop.Name}\"");
}
}

// Include root ID (only once)
if (!selectParts.Any(sp => sp.Contains($"\"Id\"")))
{
selectParts.Add($"{alias.Quote()}.{"Id".Quote()} AS \"Id\"");
}

// 2. Handle nested properties
if (param.Navigation != null)
{
foreach (var nav in param.Navigation)
{
Type navType = ResolveEntityType(nav.EntityName);
var navMeta = _metaExtractor.Extract(navType);
string navAlias = $"{alias}_{nav.EntityName}";
types.Add(navType);

// Join clause
joinParts.Add($"LEFT JOIN {navMeta.Table.Quote()} AS {navAlias.Quote()} " +
$"ON {alias.Quote()}.{"Id".Quote()} = {navAlias.Quote()}.{"ReferralId".Quote()}");

// Select child properties
foreach (var prop in navMeta.ScalarProps)
{
if (nav.Properties == null || nav.Properties.Contains(prop.Name, StringComparer.OrdinalIgnoreCase))
{
selectParts.Add($"{navAlias.Quote()}.{prop.Name.Quote()} AS \"{prop.Name}\"");
}
}

// Select child ID with correct alias for mapping (only once)
//selectParts.Add($"{navAlias.Quote()}.{"Id".Quote()} AS \"Id\"");

// Select child ID again with unique alias for splitOn
selectParts.Add($"{navAlias.Quote()}.{"Id".Quote()} AS \"{navAlias}_Id\"");
splitOnColumns.Add($"{navAlias}_Id");
}
}

return (
Types: types,
SelectClause: string.Join(", ", selectParts),
JoinClause: string.Join(" ", joinParts),
SplitOnColumns: splitOnColumns
);
}
< /code>
Сгенерированный запрос SQL: < /p>
SELECT
"T0"."ReferralSequence" AS "ReferralSequence",
"T0"."ReservationStatus" AS "ReservationStatus",
"T0"."Language" AS "Language",
"T0"."Id" AS "Id",
"T0_ReferralAppointment"."AppointmentDate" AS "AppointmentDate",
"T0_ReferralAppointment"."LegStatus" AS "LegStatus",
"T0_ReferralAppointment"."Id" AS "Id",
"T0_ReferralAppointment"."Id" AS "T0_ReferralAppointment_Id"
FROM
"Referral" AS "T0"
LEFT JOIN
"ReferralAppointment" AS "T0_ReferralAppointment" ON "T0"."Id" = "T0_ReferralAppointment"."ReferralId"
WHERE
"T0"."Id" = 1
разделить на столбце IS T0_ReferralAppointment .
Запрос возвращает правильные строки в pgadmin.

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

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

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

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

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

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение
  • Dapper неправильно картирует 1-ко многим сущностям
    Anonymous » » в форуме C#
    0 Ответы
    5 Просмотры
    Последнее сообщение Anonymous
  • Dapper неправильно картирует 1-ко многим сущностям
    Anonymous » » в форуме C#
    0 Ответы
    6 Просмотры
    Последнее сообщение Anonymous
  • Как я могу помешать подпрыгивающим сущностям проходить через стены в пигаме? [дублировать]
    Anonymous » » в форуме Python
    0 Ответы
    7 Просмотры
    Последнее сообщение Anonymous
  • Почему Firestore не картирует поле типа частного типа?
    Anonymous » » в форуме JAVA
    0 Ответы
    6 Просмотры
    Последнее сообщение Anonymous
  • Почему Firestore не картирует поле типа частного типа?
    Anonymous » » в форуме Android
    0 Ответы
    6 Просмотры
    Последнее сообщение Anonymous

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