Entity Framework 6中如何动态实现视图与键值表的关联查询
现有代码框架的Join逻辑补全
你需要先引入System.Linq.Dynamic.Core Nuget包,原生强类型Linq不支持动态拼接匿名类型的关联结果,用动态LINQ的扩展方法可以直接实现:
首先补充获取KeyValue表查询对象的逻辑,再补全循环内的Join代码:
// 假设你有DbContext实例,获取KeyValue表的可查询对象 IQueryable<KeyValueTable> kvTable = dbContext.KeyValueTables; IQueryable<BaseView> bv = GenerateBaseViewQuery(); string[] clientColumns = GetClientColumns(); string[] requiredKeys = GetClientKeys(); IQueryable finalResult = bv; foreach (string key in requiredKeys) { // 先过滤出当前Key对应的KeyValue子集,减少关联数据量 var currentKeyKv = kvTable.Where(k => k.Key == key); // 动态Join:左表关联键为ID,右表关联键为ID_BaseView,返回的结果保留左表所有字段,把当前Key的Value别名 finalResult = finalResult.Join( inner: currentKeyKv, outerKeySelector: "ID", innerKeySelector: "ID_BaseView", resultSelector: $"new(outer.*, inner.Value as {key}Data)" ); } return finalResult.Select($"new ({string.Join(",", clientColumns)})");
这里别名{key}Data需要和你clientColumns里定义的列名对应即可,和你示例SQL里的AS SomeKeyData逻辑完全一致。
更优的实现方案
循环多次Join会生成多次关联KeyValue表的SQL,当需要关联的Key数量较多时性能较差,推荐一次过滤分组后再关联的方案,只需要一次关联即可拿到所有需要的键值:
IQueryable<BaseView> bv = GenerateBaseViewQuery(); string[] clientColumns = GetClientColumns(); string[] requiredKeys = GetClientKeys(); IQueryable<KeyValueTable> kvTable = dbContext.KeyValueTables; // 先过滤出所有需要的Key的KeyValue记录,按BaseViewID分组 var kvGroupQuery = kvTable .Where(kv => requiredKeys.Contains(kv.Key)) .GroupBy(kv => kv.ID_BaseView) .Select(g => new { BaseViewId = g.Key, KeyValues = g.ToDictionary(x => x.Key, x => x.Value) }); // 一次关联即可拿到所有键值 var joinResult = bv.Join( inner: kvGroupQuery, outerKeySelector: b => b.ID, innerKeySelector: g => g.BaseViewId, resultSelector: (b, g) => new { BaseView = b, KeyValues = g.KeyValues } ); // 拼接动态Select的字段列表即可,取值方式为KeyValues["键名"] var selectColumns = clientColumns.Select(c => c.StartsWith("BaseView.") ? c : $"KeyValues[\"{c.Replace("Data", "")}\"] as {c}" ); return joinResult.Select($"new ({string.Join(",", selectColumns)})");
这个方案生成的SQL只会关联KeyValue表一次,执行效率更高,逻辑也更简洁,后续扩展也更方便。
如果需要保留没有对应键值的BaseView记录,把Join改为LeftJoin即可,Dynamic LINQ已内置该扩展方法。
内容的提问来源于stack exchange,提问作者André Reichelt
相关产品推荐
相关产品推荐

