LINQ使用DefaultIfEmpty()实现BarcodePost左外连接未达预期,求修正
解决LINQ左外连接后null值导致数据丢失的问题
你的问题核心是未处理左外连接后的null值运算:当BarcodePost中没有匹配记录时,barcode对象为null,直接访问barcode.Quantity会触发两个问题:
where条件里的material.Quantity - barcode.Quantity > 0会因null值运算返回false,整条数据被过滤select里的CurrentStock计算也会得到null值
修改方案
对barcode.Quantity做null安全处理,用??运算符将null转为0(无匹配条码记录时,默认出库数量为0):
var result = (from data in _dbContext.MaterialInwardBarcodes join material in _dbContext.MaterialInwardDetails on data.ProductId equals material.ProductId join prod in _dbContext.Products on data.ProductId equals prod.Id join vendor in _dbContext.Vendors on data.VendorId equals vendor.Id join barcode in _dbContext.BarcodePost on data.Barcode equals barcode.BarcodeNumber into barcodeGroup from barcode in barcodeGroup.DefaultIfEmpty() // 处理null值:barcode为null时,Quantity按0计算 where material.MaterialInwardHeaderId == data.RefId && material.Quantity - (barcode?.Quantity ?? 0) > 0 where data.Date <= date && data.VendorId == vendorId select new VendorWiseStock() { VendorName = vendor.Name, ProductId = prod.Id, // 同样处理select中的null运算 CurrentStock = material.Quantity - (barcode?.Quantity ?? 0) }).ToListAsync();
关键说明
barcode?.Quantity ?? 0:先通过?.安全访问barcode的Quantity(barcode为null时返回null),再用??将null替换为0- 这样既保留了左外连接的所有匹配数据,也能正确计算当前库存(无出库记录时,库存等于入库数量)
替代实现方式(方法语法)
如果偏好链式方法语法,可通过GroupJoin搭配SelectMany实现左外连接,同时处理null值:
var result = _dbContext.MaterialInwardBarcodes .Join(_dbContext.MaterialInwardDetails, data => data.ProductId, material => material.ProductId, (data, material) => new { data, material }) .Join(_dbContext.Products, dm => dm.data.ProductId, prod => prod.Id, (dm, prod) => new { dm.data, dm.material, prod }) .Join(_dbContext.Vendors, dmp => dmp.data.VendorId, vendor => vendor.Id, (dmp, vendor) => new { dmp.data, dmp.material, dmp.prod, vendor }) .GroupJoin(_dbContext.BarcodePost, dmpp => dmpp.data.Barcode, barcode => barcode.BarcodeNumber, (dmpp, barcodeGroup) => new { dmpp, barcodeGroup }) .SelectMany(x => x.barcodeGroup.DefaultIfEmpty(), (x, barcode) => new { x.dmpp, barcode }) .Where(x => x.dmpp.material.MaterialInwardHeaderId == x.dmpp.data.RefId && x.dmpp.material.Quantity - (x.barcode?.Quantity ?? 0) > 0 && x.dmpp.data.Date <= date && x.dmpp.data.VendorId == vendorId) .Select(x => new VendorWiseStock() { VendorName = x.dmpp.vendor.Name, ProductId = x.dmpp.prod.Id, CurrentStock = x.dmpp.material.Quantity - (x.barcode?.Quantity ?? 0) }) .ToListAsync();
内容的提问来源于stack exchange,提问作者Farhan Patel
相关产品推荐
相关产品推荐

