EF Core 计算属性的可选加载

Optional loading of EF Core computed properties

我正在为报告工具映射一些数据库实体。

目前,有一些计算属性取决于加载的导航属性。他们已通过 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();
        }
    }

}

当然,随着数据库大小的增加,检索这些属性的查询可能会变得非常昂贵,并且在最终报告中并不总是需要它们。

我的想法是让用户选择是否要将它们包含在最终报告中,但我还没有找到在查询时使映射可选的方法。

有没有办法自动执行此操作,或者我是否被迫具体化列表并自己单独查询这些属性,从而失去了从数据库计算属性的优势?

您需要的是利用所谓的 AutoMapper Explicit expansion 功能。这可能应该被称为“显式 属性 包含”(不要与仅用于导航的 EF Core 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)