如何编写LINQ查询:关联两表按A的Id分组统计关联行数(含PHP转LINQ)
嘿,这两个LINQ需求我帮你搞定!
问题1:A、B表关联分组查询
首先先明确实体类(和你给出的一致):
class A { public int Id { get; set; } public int BId { get; set; } public string AName { get; set; } } class B { public int Id { get; set; } public string Description { get; set; } }
要实现按A的Id分组,展示A的Id、关联B表的行数、AName,这里推荐用左连接(确保所有A记录都能被统计,包括没有关联B的情况,此时B行数为0)。以下是两种常见的LINQ写法:
查询语法(更接近SQL,易读)
var result = from a in dbContext.A // 左连接A和B,把每个A对应的B集合分组 join b in dbContext.B on a.BId equals b.Id into bGroup // 按A的Id和AName分组(同一Id的AName应该一致) group bGroup by new { a.Id, a.AName } into grouped select new { AId = grouped.Key.Id, // 统计分组内B的总数 BCount = grouped.SelectMany(b => b).Count(), AName = grouped.Key.AName };
方法语法(链式调用,灵活)
var result = dbContext.A .GroupJoin(dbContext.B, a => a.BId, // A的关联字段 b => b.Id, // B的关联字段 (a, bGroup) => new { a.Id, a.AName, Bs = bGroup }) // 关联后组合A和对应的B集合 .GroupBy(x => new { x.Id, x.AName }) // 按A的Id和AName分组 .Select(g => new { AId = g.Key.Id, BCount = g.SelectMany(x => x.Bs).Count(), AName = g.Key.AName });
如果你的需求是只统计有关联B的A记录,把GroupJoin换成普通Join即可,不过左连接的场景更通用。
问题2:PHP查询转LINQ实现
先分析原PHP查询的核心逻辑:左连接asset和assetinstance表,按asset.Id分组,统计每个asset对应的instance数量,同时返回asset的多个字段。
首先假设对应的.NET实体类(你可以根据实际情况调整):
class Asset { public int Id { get; set; } public string AssetBundleID { get; set; } public string GUID { get; set; } public string Name { get; set; } public string DisplayName { get; set; } public string Description { get; set; } public string Category { get; set; } public int TexturesSize { get; set; } public int TexturesFileSize { get; set; } public int OthersSize { get; set; } public int OthersFileSize { get; set; } } class AssetInstance { public int Id { get; set; } public int AssetId { get; set; } // 其他字段按需添加 }
注意:原PHP查询的select里有重复的字段映射(比如多次asset.Name as Id、asset.id as Id),这在SQL里是冗余的,我在LINQ里保留了合理的字段映射,如果需要严格对应重复别名,可以自行调整。
以下是LINQ实现:
查询语法
var query = from asset in dbContext.Asset // 左连接asset和assetinstance join instance in dbContext.AssetInstance on asset.Id equals instance.AssetId into instanceGroup from instance in instanceGroup.DefaultIfEmpty() // 按asset实体分组(因为asset.Id是主键,分组后每个组对应一个唯一的asset) group instance by asset into groupedAsset select new { Id = groupedAsset.Key.Id, AssetBundleID = groupedAsset.Key.AssetBundleID, GUID = groupedAsset.Key.GUID, Name = groupedAsset.Key.Name, // 原PHP重复映射为Id,若需保留请改为 Id = groupedAsset.Key.Name DisplayName = groupedAsset.Key.DisplayName, Description = groupedAsset.Key.Description, Category = groupedAsset.Key.Category, TexturesSize = groupedAsset.Key.TexturesSize, TexturesFileSize = groupedAsset.Key.TexturesFileSize, OthersSize = groupedAsset.Key.OthersSize, OthersFileSize = groupedAsset.Key.OthersFileSize, // 统计关联的instance数量(左连接后空实例不计入) InstancesCount = groupedAsset.Count(i => i != null) };
方法语法
var query = dbContext.Asset .GroupJoin(dbContext.AssetInstance, asset => asset.Id, instance => instance.AssetId, (asset, instances) => new { Asset = asset, Instances = instances }) // 展开左连接的结果,空实例用DefaultIfEmpty()填充 .SelectMany(x => x.Instances.DefaultIfEmpty(), (x, instance) => new { x.Asset, Instance = instance }) // 按asset分组 .GroupBy(x => x.Asset) .Select(g => new { Id = g.Key.Id, AssetBundleID = g.Key.AssetBundleID, GUID = g.Key.GUID, Name = g.Key.Name, DisplayName = g.Key.DisplayName, Description = g.Key.Description, Category = g.Key.Category, TexturesSize = g.Key.TexturesSize, TexturesFileSize = g.Key.TexturesFileSize, OthersSize = g.Key.OthersSize, OthersFileSize = g.Key.OthersFileSize, InstancesCount = g.Count(item => item.Instance != null) });
这个实现完全对应原PHP查询的逻辑:左连接、分组、统计实例数量,同时返回指定的asset字段。
内容的提问来源于stack exchange,提问作者kwestia
相关产品推荐
相关产品推荐

