EF core line group от многих ко многим - PullRequest
0 голосов
/ 17 ноября 2018

У меня есть таблица взаимосвязей «многие ко многим», где я пытаюсь отобразить список отчетов в таблице.

Мой стол выглядит так:

Таблица отчетов:

Id| ReportName |
1 | report 1   |
2 | report 2   |
3 | report 3   |

Таблица категорий отчетов:

Id| Name     |
1 | General  |
2 | Specific |

Таблица соединений ReportMapping:

Id| ReportId | CategoryId |
1 | 1        | 1          |
2 | 1        | 2          |
3 | 2        | 1          |
4 | 2        | 2          |

Отчеты могут иметь несколько категорий, в этом примере их всего 2, но их может быть много, например, скажем, 1 отчет может иметь 5 категорий, таких как Общие, Специальные, Тест2, Тест3 и Тест4

Я бы хотел отобразить формат в таблице / списке в моем приложении .net core примерно так:

ReportId| Report Name | Report Categories
1       | report 1    | General, Specific
2       | report 2    | General, Specific

У меня проблемы с настройкой работы сервера sql и ядра EF linq. Любые указатели о том, как начать это? Пока что я могу объединить таблицы, но не знаю, как объединить мои результаты в одну строку для отчетов, которые имеют несколько категорий. Я получаю такие вещи, как показано ниже, а не желаемый результат, как в примере выше:

ReportId | Report Name | Report Categories
1        | report 1    | General
1        | report 1    | Specific
2        | report 2    | General
2        | report 2    | Specific

Любая помощь будет оценена, спасибо!

1 Ответ

0 голосов
/ 17 ноября 2018

Модель, которую вы описываете, почти идентична модели Post / Tag из Пример "многие ко многим" в документации EF Core.

Таким образом, у вас будет 3 класса, представляющих записи таблицы

public class Report
{
    public int Id { get; set; }
    public string ReportName { get; set; }
    public ICollection<ReportMapping> Mappings { get; set; }  // navigation
}

public class ReportCategory
{
    public int Id { get; set; }
    public string Name { get; set; }
    public ICollection<ReportMapping> Mappings { get; set; } // navigation
}

public class ReportMapping
{
    public int Id { get; set; }
    public int ReportId { get; set; }
    public int CategoryId { get; set; }
    public Report Report { get; set; } // navigation
    public ReportCategory Category { get; set; } // navigation
}

и 3 DbSet s, представляющие ваши таблицы:

public DbSet<Report> Reports { get; set; }
public DbSet<ReportCategory> ReportCategories { get; set; }
public DbSet<ReportMapping> ReportMappings { get; set; }

Обратите внимание, что свойство Id (столбец) в объекте соединения (таблице) является избыточным, поэтому, если вы не ограничены существующей базой данных, рассмотрите возможность ее удаления и настройте составной PK, как в примере

modelBuilder.Entity<ReportMapping>()
    .HasKey(e => new { e.ReportId, e.CategoryId });

Также обратите внимание на свойства, помеченные // navigation. Это так называемые свойства навигации (см. Определение терминов ), которые представляют собой концы отношений и позволяют получить доступ к связанным данным внутри запросов LINQ. без использования join конструкций - см. Не используйте Linq Join. Перейдите! и это EF (Core) рекомендуемый / предпочтительный способ написания запросов LINQ.

Итак, это ваша модель базы данных. Поскольку вы хотите запрос, возвращающий конкретный тип результата, начните с определения класса, который представляет этот результат (например, DTO, ViewModel и т. Д.), Например:

public class ReportInfo
{
    public int ReportId { get; set; }
    public string ReportName { get; set; }
    public IEnumerable<string> ReportCategories { get; set; }
}

Обратите внимание, что я определяю ReportCategories как последовательность строк, а не как одну строку. Это связано с тем, что, во-первых, конкатенация строк набора результатов изначально не поддерживается базами данных, а во-вторых, конкатенация через запятую является лишь одним из многих способов представления этих данных. В целом форматирование данных является обязанностью клиентов. Таким образом, вы возвращаете данные в их исходном формате (список строк) и позволяете клиенту форматировать их (в этом случае это легко сделать с помощью string.Join(",", info.ReportCategories)).

Наконец, фактический запрос. При наличии свойств навигации это довольно просто - в основном просто Select s:

var result = db.Reports
    .Select(r => new ReportInfo
    {
        ReportId = r.Id,
        ReportName = r.ReportName,
        ReportCategories = r.Mappings
            .Select(m => m.Category.Name)
            .ToList() // <-- to avoid N + 1 subquery in EF Core 2.1+
    })
    .ToList();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...