如何将指定SQL左连接查询转换为Entity Framework Core查询?
嘿,我来帮你搞定这个EF Core的查询转换问题~首先得先明确一个关键点:你写的SQL语句虽然用了LEFT JOIN,但后面的WHERE ProductCategory.CategoryID = 1会把左连接中没有匹配到ProductCategory的Products记录过滤掉——因为这些记录的ProductCategory字段都是NULL,NULL不等于1,所以实际这条SQL的效果其实和INNER JOIN是完全一致的。
接下来分两种场景给你对应的EF Core写法:
场景1:和原SQL效果一致(等价于内连接)
这时候你的写法其实可以简化,不过要注意几个细节:如果你不需要返回ProductCategory的关联数据,那甚至不用加Include;但如果要加载关联数据的话,正确的写法应该是:
var result = _context.Products .Include(p => p.ProductCategory) // 仅当需要返回ProductCategory数据时添加 .Where(p => p.ProductCategory != null && p.ProductCategory.CategoryID == CategoryID) .ToList();
EF Core会自动把这个查询转换成等价的内连接SQL,和你原来的SQL效果完全匹配。你之前的写法没加Include时,EF Core不会自动加载关联的ProductCategory,导致p.ProductCategory为null,Where条件要么报错要么返回空;加了Include但没加null判断的话,遇到没有对应Category的Product时会抛出空引用异常,所以一定要加上p.ProductCategory != null的判断。
场景2:真正的左连接(保留无匹配Category的Products)
如果你确实想要左连接的效果——也就是即使Products没有对应的ProductCategory记录,也要保留这些Products(此时ProductCategory为null),同时只匹配那些ProductCategory的CategoryID=1的记录,那你需要把过滤条件放在连接条件里,而不是Where子句中,这时候可以用两种写法实现:
LINQ查询语法(更易读)
var result = from product in _context.Products join category in _context.ProductCategory on product.ProductCode equals category.ProductCode into joinedCategories from subCategory in joinedCategories.DefaultIfEmpty() where subCategory == null || subCategory.CategoryID == CategoryID select new { Product = product, ProductCategory = subCategory };
方法链写法
var result = _context.Products .GroupJoin( _context.ProductCategory, product => product.ProductCode, category => category.ProductCode, (product, relatedCategories) => new { Product = product, RelatedCategories = relatedCategories } ) .SelectMany( joinedData => joinedData.RelatedCategories.DefaultIfEmpty(), (joinedData, matchedCategory) => new { Product = joinedData.Product, ProductCategory = matchedCategory } ) .Where(item => item.ProductCategory == null || item.ProductCategory.CategoryID == CategoryID) .ToList();
不过要注意,这种写法和你原来的SQL逻辑是不一样的,原SQL会过滤掉没有匹配Category的Product,而这个真正的左连接写法会保留它们。
内容的提问来源于stack exchange,提问作者Rick Jolly

