Получение дочерних сущностей из CrudAppService в abp.io с помощью .Net 5 EF

Я использую последнюю версию ABP от abp.io и имею две сущности с отношением "многие-многие". Эти:

public class GroupDto : AuditedEntityDto<Guid>
{
    public GroupDto()
    {
        this.Students = new HashSet<Students.StudentDto>();
    }

    public string Name { get; set; }
    public bool IsActive { get; set; } 
    public virtual ICollection<Students.StudentDto> Students { get; set; }
}

а также

public class StudentDto : AuditedEntityDto<Guid>
{
    public StudentDto()
    {
        this.Groups = new HashSet<Groups.GroupDto>();
    }

    public string Name { get; set; }
    public bool IsActive { get; set; }

    public virtual ICollection<Groups.GroupDto> Groups { get; set; }
}

Я установил следующий тест, чтобы проверить, получаю ли я связанные объекты, и, к сожалению, свойство Students всегда пусто.

public async Task Should_Get_List_Of_Groups()
{
    //Act
    var result = await _groupAppService.GetListAsync(
        new PagedAndSortedResultRequestDto()
    );

    //Assert
    result.TotalCount.ShouldBeGreaterThan(0);
    result.Items.ShouldContain(g => g.Name == "13Ck" && g.Students.Any(s => s.Name == "Michael Studentman"));
}

То же самое верно и для эквивалентного теста для List из Students, свойство Groups всегда пусто.

Я нашел один связанный ответ для abp.io (который не совпадает с ABP, это более новая / другая структура) https://stackoverflow.com/a/62913782/7801941, но, к сожалению, когда я добавляю эквивалент своего StudentAppService, я получаю сообщение об ошибке -

CS1061 'IRepository ‹Student, Guid›' не содержит определения для 'Include', и не может быть найден доступный метод расширения 'Include', принимающий первый аргумент типа 'IRepository ‹Student, Guid›' (отсутствует ли директива using или ссылка на сборку?)

Код для этого ниже, и ошибка возникает в строке, которая начинается с .Include.

public class StudentAppService :
    CrudAppService<
        Student, //The Student entity
        StudentDto, //Used to show students
        Guid, //Primary key of the student entity
        PagedAndSortedResultRequestDto, //Used for paging/sorting
        CreateUpdateStudentDto>, //Used to create/update a student
    IStudentAppService //implement the IStudentAppService
{
    private readonly IRepository<Students.Student, Guid> _studentRepository;

    public StudentAppService(IRepository<Student, Guid> repository)
        : base(repository)
    {
        _studentRepository = repository;
    }

    protected override IQueryable<Student> CreateFilteredQuery(PagedAndSortedResultRequestDto input)
    {
        return _studentRepository
             .Include(s => s.Groups);
    }
}

Это реализует этот интерфейс

public interface IStudentAppService :
    ICrudAppService< // Defines CRUD methods
        StudentDto, // Used to show students
        Guid, // Primary key of the student entity
        PagedAndSortedResultRequestDto, // Used for paging/sorting
        CreateUpdateStudentDto> // Used to create/update a student
{
    //
}

Может ли кто-нибудь пролить свет на то, как я должен получать доступ к связанным объектам с помощью AppServices?

Изменить: Спасибо тем, кто ответил. Чтобы уточнить, я ищу решение / объяснение того, как получить доступ к объектам, которые имеют отношение «многие-многие», с помощью AppService, а не репозитория.

Чтобы помочь с этим, я загрузил zip-файл со всем исходным кодом вместе со многими изменениями, которые я пробовал, чтобы заставить это работать, здесь.


person jcreek    schedule 07.03.2021    source источник
comment
ABP - это фреймворк для создания шаблонного кода. Это не EF Core 5, и не нужно использовать EF 5. Его классы Repositry также не нужны. Ошибка кажется довольно ясной и четко объяснена в тексте ошибки - 'IRepository<Student, Guid>' does not contain a definition for 'Include'. Вы пытались использовать метод, предназначенный для использования в EF Core и LINQ в несвязанном Repository классе. Используя эти общие классы репозитория, вы больше не можете работать с сущностями и их отношениями.   -  person Panagiotis Kanavos    schedule 08.03.2021
comment
Include можно использовать только в IQueryable или DbSet, что означает, что вам нужен DbContext или DbSet, который был скрыт IRepository. Это лишь одна из причин, почему общие репозитории являются анти шаблоном. В специализированном репозитории у вас может быть метод WithGroups, возвращающий _dbContext.Students.Include(s=>s.Groups). Или вы можете добавить к IRepository метод .... Include, который вызывает Include.   -  person Panagiotis Kanavos    schedule 08.03.2021


Ответы (1)


Вы можете отложить загрузку, быстро загрузить или настроить поведение по умолчанию для сущности для вложенных коллекций.

Конфигурация по умолчанию:

Configure<AbpEntityOptions>(options =>
{
    options.Entity<Student>(studentOptions =>
    {
        studentOptions.DefaultWithDetailsFunc = query => query.Include(o => o.Groups);
    });
});

Стремительная нагрузка:

//Get a IQueryable<T> by including sub collections
var queryable = await _studentRepository.WithDetailsAsync(x => x.Groups);
        
//Apply additional LINQ extension methods
var query = queryable.Where(x => x.Id == id);
        
//Execute the query and get the result
var student = await AsyncExecuter.FirstOrDefaultAsync(query);

Или отложенная загрузка:

var student = await _studentRepository.GetAsync(id, includeDetails: false);
//student.Groups is empty on this stage

await _studentRepository.EnsureCollectionLoadedAsync(student, x => x.Groups);
//student.Groups is filled now

Дополнительную информацию можно найти в документации.

Изменить: возможно, вы забыли добавить репозитории по умолчанию, например:

services.AddAbpDbContext<MyDbContext>(options =>
{
    options.AddDefaultRepositories();
});

Хотя я хотел бы предложить вам использовать собственные репозитории, такие как

IStudentRepository:IRepository<Student,Guid>

Чтобы вы могли лучше масштабировать свой репозиторий.

person gterdem    schedule 08.03.2021
comment
Спасибо за ваш ответ! Я чувствую, что мне здесь не хватает чего-то фундаментального. Если я добавлю конфигурацию по умолчанию из вашего ответа к методу ConfigureServices в моем модуле в проекте EntityFrameworkCore, у меня все равно будет такая же проблема при попытке доступа к нему через службу приложений, которая извлекает объект StudentDto. Например, мой метод Should_Get_List_Of_Students почти идентичен приведенному выше примеру Should_Get_List_Of_Groups, и у него все еще есть та же проблема. Как я могу получить поведение по умолчанию для определенных сущностей, которое будет загружаться через AppService, а не через репозиторий? - person jcreek; 08.03.2021
comment
@jcreek Я обновил свой ответ, добавив более подробную информацию. - person gterdem; 08.03.2021
comment
Привет @gterdem, спасибо за ответ. Чтобы уточнить, я ищу решение / объяснение того, как получить доступ к объектам, которые имеют отношение «многие-многие», с помощью AppService, а не репозитория. Чтобы помочь с этим, я загрузил zip-файл со всем исходным кодом вместе со многими изменениями, которые я пробовал, чтобы заставить это работать, здесь. - person jcreek; 10.03.2021