Доступна или возможна ли такая вещь с помощью Dapper для автоматического расширения членов класса?

Есть ли способ сделать что-то подобное? Допустим, у меня есть два класса:

public class Class_A
{
  public string Name {get;}
  public string Age  {get;}
  public int    Key  {get;}
}
public class Class_B
{
  public string Doors {get;}
  public string Windows  {get;}
  public int    Key  {get;}
}

а затем комбинированный класс следующим образом:

public class Class_C
{
  public Class_A CA {get;}
  public Class_B CB {get;}
}

теперь скажем, я говорю

_connection.Query<Class_C>("A SQL that returns results from JOIN of Clas_A and Class_B")

Тогда он сможет каким-то образом знать, какое поле чему сопоставить. Потому что в противном случае мне придется снова скопировать и вставить поля этих двух классов внутри Class_C, вот так:

public class Class_C
{
      public string Name {get;}
      public string Age  {get;}
      public string Doors {get;}
      public string Windows {get;}
}

Не совсем понятно, но я думаю, вам стоит посмотреть Learndapper.com/dapper-query/selecting-multiple-results

Steve 17.04.2024 23:41

У меня есть один набор результатов: поскольку SQL является результатом JOIN между двумя таблицами, поэтому некоторые данные для этого JOIN поступают из Table_A, которая сопоставляется с Class_A, а некоторые данные поступают из Table_B, которые сопоставляются с Class_B: Таким образом, конечный результат класса - это поля из ОБА Class_A и Class_B, поэтому я надеялся, что если бы у меня был Class_C, который вместо копирования всех полей в нем снова, я мог бы просто сослаться на Class_A и Class_B, и он автоматически расширил бы свойства этих классов.

Bohn 17.04.2024 23:47

Как вы связываете A и B в базе данных?

Daniel Manta 17.04.2024 23:50

@derloopkat: Просто представьте, что есть какой-то ключ, по которому их можно объединить в SQL. Я также добавил поле «Ключ» в оба примера.

Bohn 17.04.2024 23:54

Отношения 1-1?

Steve 17.04.2024 23:55

@Steve: В моем случае да, это 1-1. ЛЕВОЕ СОЕДИНЕНИЕ. лайк Table_A a LEFT JOIN Table_B b on a.Key = b.Key

Bohn 17.04.2024 23:56
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
6
96
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Не проверялось, но я думаю, вы могли бы написать это:

string cmd = @"select a.Key, a.Name, a.Age, 
                      b.Key, b.Doors, b.Windows 
               from Class_A a INNER JOIN Class_B b on a.Key = b.Key";

var listOfC = connection.Query<Class_A, Class_B, Class_C>(cmd, (a,b) =>
{
    Class_C c = new Class_C();
    c.CA = a;
    c.CB = b;
    return c;
    
}, splitOn:"Key");

Если вы просто хотите использовать Class_C со всеми свойствами A и B, тогда это просто

string cmd = @"select a.Key, a.Name, a.Age, 
                      b.Doors, b.Windows 
               from Class_A a INNER JOIN Class_B b on a.Key = b.Key";

var listOfC = connection.Query<Class_C>(cmd);

и Dapper просто сопоставит поля со свойствами Class_C.

Спасибо, Class_C на самом деле не нужен. Я придумал Query<Class_C> только потому, что в результате JOIN есть поля, доступные как в Class_A, так и в Class_B, и я не смог найти способ использовать синтаксис connection.Query<T> для моего окончательного результата. Я бы мог пройти connection.Query<dynamic>, но это ещё хуже! поэтому я надеялся, что каким-то образом можно будет динамически объединить поля этих двух классов.

Bohn 18.04.2024 00:10

Каким будет T, зависит от вашего варианта использования. Я думаю, что в отношениях 1-1 хорошо иметь класс, все свойства которого точно соответствуют полям, полученным при объединении.

Steve 18.04.2024 00:18

Да, точно. T похож на тот Class_C, который, как вы сказали, «имеет все свойства, точно соответствующие полям, полученным при объединении». НО, чтобы иметь такой класс, я копирую свойства Class_A и Class_B в Class_C. И я хотел посмотреть, есть ли лучший способ, чем дублировать и копировать эти свойства в Class_C.

Bohn 18.04.2024 00:20
Ответ принят как подходящий

Следуя вашим комментариям, для устранения всей избыточности вы можете добавить PropertyB к классу A и позволить Dapper связать это свойство с результатом вашего запроса.

public class A
{
    public string Name { get; set; }
    public string Age { get; set; }
    public int Key { get; set; }
    public B PropertyB { get; set; }
}

public class B
{
    public string Doors { get; set; }
    public string Windows { get; set; }
    public int Key { get; set; }
}

Запрос:

SELECT * FROM A INNER JOIN B ON A.[Key] = B.[Key];

Результатами являются поля в следующем порядке Name, Age, Key, Doors, Windows, Key.

Итак, если разделить на Doors:

  • Группа слева: A (Name, Age, Key)
  • Группа справа — B (Doors, Windows, Key).
var results = connection.Query<A, B, A>(
        sql,
        (a, b) =>
        {
            a.PropertyB = b;
            return a;
        },
        splitOn: "Doors")
    .Distinct()
    .ToList();

Query<A, B, A> означает, что слева — это тип A, справа — это тип B, а объединенный результат A генерируется вышеуказанной функцией.

Для получения дополнительной информации см. документацию Dapper Multi-Mapping Result. Имеется поддержка сопоставления «один к одному» и «один ко многим».

Спасибо за объяснение. Но эта часть «левая — это тип A, правая — это тип B, а объединенный результат — это A», то есть вы имеете в виду, что она поместит результаты в класс A? но у класса недостаточно свойств, чтобы вместить все четыре вещи из JOIN. Я неправильно понял это?

Bohn 18.04.2024 13:35
A имеет PropertyB . Если вы поставите точку останова a.PropertyB = b;, вы увидите, что она делает. Вы получаете первые 3 поля в A и последние 3 поля в A.PropertyB.
Daniel Manta 18.04.2024 13:40

В учебнике Dapper они есть invoice.InvoiceDetail = invoiceDetail;, поэтому вы получаете счет с подробностями счета.

Daniel Manta 18.04.2024 13:43

Спасибо чувак. Я сяду читать учебник. Нет спасения от того, чтобы не учиться этому.

Bohn 18.04.2024 13:51

Другие вопросы по теме