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
"r"."Id",
"r"."ReservationStatus",
"r"."Language",
"r"."ReferralSource",
"ra"."Id",
"ra"."AppointmentDate",
"ra"."AppointmentTime",
"ra"."LegSequence",
"ra"."LegStatus",
"ra"."ReferralId"
FROM
"Referral" AS "r"
LEFT JOIN "ReferralAppointment" AS "ra" ON "r"."Id" = "ra"."ReferralId"
WHERE
"r"."Id" = 1
разделить на столбце ID ID .
Тот же запрос работал со статическими типами и жестким запросом. Я использовал тот же жестко -кодированный запрос с динамической функцией, с тем же Sploton. Но динамическая функция не заполняет дочерние коллекции. Это пусто, а не ноль. AI говорит, что в случае статического Dapper знает (_db.queryasync ), типы статически. Это проблема.
Я спросил, могу ли я использовать свои динамические типы в общей функции (_db.queryasync ), он предложил мне вызвать QueryAsync через отражение. Но после возвращения null: < /p>

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

var method = typeof(IDbConnection).GetMethods()
.FirstOrDefault(m => m.Name == "QueryAsync" && m.IsGenericMethod);
Запрос возвращает правильные строки в 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#»