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)
我正在为报告工具映射一些数据库实体。
目前,有一些计算属性取决于加载的导航属性。他们已通过 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)