基于ABP框架与EF Core实现带供应商价格对比及最低价标识的产品数据查询
基于ABP框架与EF Core实现带供应商价格对比及最低价标识的产品数据查询
嘿,针对你在ABP+EF Core项目里遇到的产品供应商价格对比展示问题,我给你梳理一套可行的实现方案,从后端数据查询到前端Kendo Grid展示都安排明白!
一、后端数据查询与处理(EF Core + ABP)
首先咱们得先对齐核心实体的关系,假设你的项目里有这几个关键实体:
public class Product : FullAuditedAggregateRoot<Guid> { public string Name { get; set; } // 其他产品属性(比如描述、分类等) public ICollection<ProductSupplierPrice> SupplierPrices { get; set; } } public class Supplier : FullAuditedAggregateRoot<Guid> { public string Name { get; set; } // 其他供应商属性(比如地址、联系方式等) } public class ProductSupplierPrice : Entity<Guid> { public Guid ProductId { get; set; } public Product Product { get; set; } public Guid SupplierId { get; set; } public Supplier Supplier { get; set; } public decimal Price { get; set; } }
接下来在你的ABP应用服务里,编写查询方法——既要拉取产品的所有供应商价格,还要自动计算每个产品的最低价供应商信息:
public async Task<List<ProductPriceComparisonDto>> GetProductPriceComparisonAsync() { // 用ABP仓储关联查询产品、供应商价格及供应商信息 var productsWithPrices = await _productRepository .Include(p => p.SupplierPrices) .ThenInclude(ps => ps.Supplier) .ToListAsync(); // 转换成前端友好的DTO,同时完成最低价计算 return productsWithPrices.Select(p => new ProductPriceComparisonDto { ProductId = p.Id, ProductName = p.Name, // 收集当前产品的所有供应商价格明细 SupplierPrices = p.SupplierPrices.Select(ps => new SupplierPriceDto { SupplierId = ps.SupplierId, SupplierName = ps.Supplier.Name, Price = ps.Price }).ToList(), // 筛选出当前产品的最低价供应商 CheapestSupplier = p.SupplierPrices .OrderBy(ps => ps.Price) .FirstOrDefault() is var cheapestPrice ? new CheapestSupplierDto { SupplierId = cheapestPrice?.SupplierId ?? Guid.Empty, SupplierName = cheapestPrice?.Supplier.Name ?? string.Empty, Price = cheapestPrice?.Price ?? 0 } : null }).ToList(); } // 配套的DTO类,用于前后端数据传输 public class ProductPriceComparisonDto { public Guid ProductId { get; set; } public string ProductName { get; set; } public List<SupplierPriceDto> SupplierPrices { get; set; } public CheapestSupplierDto CheapestSupplier { get; set; } } public class SupplierPriceDto { public Guid SupplierId { get; set; } public string SupplierName { get; set; } public decimal Price { get; set; } } public class CheapestSupplierDto { public Guid SupplierId { get; set; } public string SupplierName { get; set; } public decimal Price { get; set; } }
二、前端数据转换适配Kendo Grid透视结构
因为你想用Kendo Grid做透视表展示(把供应商作为列),所以需要把后端返回的结构化数据转换成透视格式:
// 假设后端接口返回的数据存在productComparisonData变量中 // 先收集所有唯一的供应商名称,用于生成动态列 const allSuppliers = [...new Set(productComparisonData.flatMap(p => p.supplierPrices.map(sp => sp.supplierName)))]; // 转换数据为透视表适配格式 const pivotData = productComparisonData.map(product => { const row = { productId: product.productId, productName: product.productName, // 把最低价供应商信息打包成字符串,方便后续展示 cheapestSupplier: `${product.cheapestSupplier.supplierName} ($${product.cheapestSupplier.price})` }; // 为每个供应商添加对应的价格列 allSuppliers.forEach(supplier => { const price = product.supplierPrices.find(sp => sp.supplierName === supplier)?.price || '-'; row[supplier] = price; }); return row; });
三、配置Kendo Grid实现展示与最低价高亮
最后配置Kendo Grid,动态生成供应商列,同时给最低价单元格添加高亮样式:
// 构建Grid的列配置 const columns = [ { field: 'productId', title: 'Product ID' }, { field: 'productName', title: 'Product Name' }, // 动态生成供应商列,并添加最低价高亮逻辑 ...allSuppliers.map(supplier => ({ field: supplier, title: supplier, template: function(dataItem) { const currentPrice = dataItem[supplier]; // 判断当前价格是否为该产品的最低价,是的话高亮 if (currentPrice === dataItem.cheapestSupplier.split('$')[1]) { return `<span style="color: green; font-weight: bold;">$${currentPrice}</span>`; } return currentPrice === '-' ? '-' : `$${currentPrice}`; } })), { field: 'cheapestSupplier', title: 'Cheapest Supplier' } ]; // 初始化Kendo Grid $("#grid").kendoGrid({ dataSource: { data: pivotData, pageSize: 10 }, columns: columns, sortable: true, pageable: true });
额外小提示
- 如果供应商数量较多,建议给Grid加上列过滤或冻结列功能,提升用户体验;
- 后端查询时可以根据需求添加分页、过滤条件,避免数据量过大拖慢性能;
- 如果需要实时更新价格,可以结合ABP的SignalR功能实现数据推送。
备注:内容来源于stack exchange,提问作者aabdan
相关产品推荐
相关产品推荐

