如何在LINQ Core中实现行转列与逆透视?附SQL参考代码
在LINQ Core中实现UNPIVOT(逆透视)功能
好问题!LINQ本身并没有像SQL里那样提供直接的UNPIVOT内置方法,但我们可以通过灵活的方式实现完全相同的逆透视效果,核心思路是利用SelectMany将每个“宽行”拆解为多个“窄行”。
先明确数据模型
假设你的透视后数据(对应SQL里的#temp表)对应的C#模型是这样的:
public class PivotedTranslation { public string ResourceName { get; set; } public string ENText { get; set; } public string FRText { get; set; } public string ZHText { get; set; } public string DEText { get; set; } public string ITText { get; set; } public string JAText { get; set; } public string PTText { get; set; } public string PTBRText { get; set; } // 对应SQL中的[PT-BRText] public string RUText { get; set; } public string ESText { get; set; } public string SVText { get; set; } }
而你想要的逆透视后的数据模型(对应SQL里的UnpivotTranslation结果)是:
public class UnpivotedTranslation { public Guid Id { get; set; } public string ResourceName { get; set; } public string LanguageID { get; set; } public string Translation { get; set; } }
实现逆透视的LINQ查询
使用SelectMany方法,将每个PivotedTranslation对象拆分为多个UnpivotedTranslation对象,每个对象对应一个语言列:
// 假设pivotedData是你的透视后数据源(可以是EF Core的DbSet,或者内存集合) var unpivotedData = pivotedData.SelectMany(p => new[] { new UnpivotedTranslation { Id = Guid.NewGuid(), ResourceName = p.ResourceName, LanguageID = "ENText", Translation = p.ENText }, new UnpivotedTranslation { Id = Guid.NewGuid(), ResourceName = p.ResourceName, LanguageID = "FRText", Translation = p.FRText }, new UnpivotedTranslation { Id = Guid.NewGuid(), ResourceName = p.ResourceName, LanguageID = "ZHText", Translation = p.ZHText }, new UnpivotedTranslation { Id = Guid.NewGuid(), ResourceName = p.ResourceName, LanguageID = "DEText", Translation = p.DEText }, new UnpivotedTranslation { Id = Guid.NewGuid(), ResourceName = p.ResourceName, LanguageID = "ITText", Translation = p.ITText }, new UnpivotedTranslation { Id = Guid.NewGuid(), ResourceName = p.ResourceName, LanguageID = "JAText", Translation = p.JAText }, new UnpivotedTranslation { Id = Guid.NewGuid(), ResourceName = p.ResourceName, LanguageID = "PTText", Translation = p.PTText }, new UnpivotedTranslation { Id = Guid.NewGuid(), ResourceName = p.ResourceName, LanguageID = "PT-BRText", Translation = p.PTBRText }, new UnpivotedTranslation { Id = Guid.NewGuid(), ResourceName = p.ResourceName, LanguageID = "RUText", Translation = p.RUText }, new UnpivotedTranslation { Id = Guid.NewGuid(), ResourceName = p.ResourceName, LanguageID = "ESText", Translation = p.ESText }, new UnpivotedTranslation { Id = Guid.NewGuid(), ResourceName = p.ResourceName, LanguageID = "SVText", Translation = p.SVText } }) // 可选:过滤掉空的翻译值,和你SQL里MAX聚合后过滤空值的逻辑对应 .Where(ut => !string.IsNullOrEmpty(ut.Translation)) .OrderBy(ut => ut.ResourceName);
关键说明
SelectMany是实现逆透视的核心:它把单个源对象“展开”为多个目标对象,完美对应SQLUNPIVOT将列转为行的逻辑。- 如果你的数据源是EF Core的
DbSet,这个LINQ查询会被EF Core自动转换为等价的SQL语句执行,性能和你手写的UNPIVOTSQL相近。 - 要是你想避免硬编码列名(比如语言列可能动态变化),可以用反射遍历
PivotedTranslation的属性,但注意反射方式在EF Core中无法被转换为SQL,只适合内存中的数据处理。
内容的提问来源于stack exchange,提问作者Shardul
相关产品推荐
相关产品推荐

