Необязательная загрузка вычисляемых свойств ядра EF

c# #asp.net #entity-framework-core #automapper

#c# #asp.net #entity-framework-core #automapper

Вопрос:

Я работаю над отображением нескольких объектов базы данных для инструмента отчетности.

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

 public class Customer 
{
    public long Id { get; set; }
    public string Name { get; set; }

    public virtual ICollection<Foo> Foos { get; set; }
    public virtual ICollection<Bar> Bars { get; set; }
}

public class CustomerDto
{
    public long Id { get; set; }
    public string Name { get; set; }

    public long TotalNumberOfFoos { get; set; }
    public long NumberOfBarsWithCondition { get; set; }    
}


public class CustomerProfile : Profile
{
    public CustomerProfile()
    {
        CreateMap<Customer, CustomerDto>()
            .ForMember(d => d.TotalNumberOfFoos, p => p.MapFrom(c => c.Foos.Count))
            .ForMember(d => d.NumberOfBarsWithCondition, p => p.MapFrom(c => c.Bars.Where(b => b.BarProperty == "something").Count()));
    }
}

public class CustomerController : Controller
{
    public async Task<List<CustomerDto>> CustomersByName(string name)
    {
        using (var db = new MyDbContext())
        {
            return await db.Customers
                .ProjectTo<CustomerDto>(_mapper.ConfigurationProvider)
                .Where(c => c.Name == name).ToListAsync();
        }
    }

}
 

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

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

Есть ли способ сделать это автоматически, или я вынужден материализовать список и самостоятельно запрашивать эти свойства отдельно, теряя преимущество наличия вычисляемых свойств из базы данных?

Комментарии:

1. Я предполагаю, что вы ищете явное расширение AutoMapper. Что, вероятно, следует называть «явным включением свойств» (не следует смешивать с ядром EF Include , которое предназначено только для навигации).

2. @IvanStoev Это именно то, что мне было нужно! Я протестировал его, и он творит чудеса. Я был бы рад отметить это как ответ, если вы опубликуете его как один.

Ответ №1:

Что вам нужно, так это использовать так называемую функцию явного расширения AutoMapper. Который, вероятно, следует называть «явным включением свойств» (не следует смешивать с ядром EF Include , которое предназначено только для навигации), поскольку он работает для любого целевого свойства, и то, что он делает, скорее включает его автоматически в сгенерированную проекцию ( Select ), включает его только при явном выборе.

Итак, сначала вам нужно настроить такие свойства, как ExplicitExpansion() , например

 CreateMap<Customer, CustomerDto>()
    .ForMember(d => d.TotalNumberOfFoos, p =>
    {
        p.MapFrom(c => c.Foos.Count);
        p.ExplicitExpansion();
     })
    .ForMember(d => d.NumberOfBarsWithCondition, p =>
    {
        p.MapFrom(c => c.Bars.Where(b => b.BarProperty == "something").Count());
        p.ExplicitExpansion();
    });
 

Теперь по умолчанию они не будут заполнены. Используйте дополнительные аргументы ProjectTo , чтобы передать, какие из них вы хотите «развернуть» (включить), например

 .ProjectTo<CustomerDto>(_mapper.ConfigurationProvider, e => e.TotalNumberOfFoos)