【问题标题】:SQL Unions with table counts using EntityFramework LINQ query使用 EntityFramework LINQ 查询的具有表计数的 SQL 联合
【发布时间】:2021-11-05 20:19:29
【问题描述】:

我正在尝试使用 LINQ 和实体框架复制下面的 SQL,但无法弄清楚应该如何编写。

我的简单 LINQ 版本对每个表进行查询

public IActionResult Index()
{
      dynamic view = new ExpandoObject();

      view.AppUsers             = Context.AppUsers.Count();
      view.CustomerShops        = Context.CustomerShops.Count();
      view.FavouriteOrders      = Context.FavouriteOrders.Count();
      view.Items                = Context.Items.Count();
      view.ItemVariations       = Context.ItemVariations.Count();
      view.MenuCategories       = Context.MenuCategories.Count();
      view.MenuCategoryProducts = Context.MenuCategoryProducts.Count();
      view.Orders               = Context.Orders.Count();
      view.Products             = Context.Products.Count();
      view.ProductVariations    = Context.ProductVariations.Count();
      view.Shops                = Context.Shops.Count();
      view.Staffs               = Context.Staffs.Count();

      return View(view);
}

我不时使用这种模式来报告我的列数,并认为这在 LINQ 中应该很容易做到,但到目前为止还没有运气。

这种纯 SQL UNION 只会生成 1 个 SQL 请求,而不是每个表一个请求。

select * from (
  select 'asp_net_roles' as type, count(*) from asp_net_roles
  union
  select 'asp_net_user_roles' as type, count(*) from asp_net_user_roles
  union
  select 'asp_net_users' as type, count(*) from asp_net_users
  union
  select 'app_users' as type, count(*) from app_users
  union
  select 'shops' as type, count(*) from shops
  union
  select 'staffs' as type, count(*) from shops
  union
  select 'items' as type, count(*) from items
  union
  select 'item_variations' as type, count(*) from item_variations
  union
  select 'products' as type, count(*) from products
  union
  select 'product_variations' as type, count(*) from product_variations
  union
  select 'menu_categories' as type, count(*) from menu_categories
) as counters
order by 1;

我看到了部分实现 [linq-group-by-multiple-tables] (https://stackoverflow.com/a/3435503/473923),但这是基于分组数据。

仅供参考:我是 C#/Linq 新手,如果这个接缝很明显,我很抱歉。

【问题讨论】:

  • 所以您的Context.AppUsers.Count() 没有返回任何内容或出现问题?我看到Context.AppUsers.Count() 它返回了key 和value 对的总数,如果我误解了,请告诉我。
  • Context.AppUsers.Count() 返回计数(是),但对于 50 个表,我必须调用它 50 次,但使用联合我只能调用一次,我正在尝试在 LINQ 中做联合
  • 检查这个我的答案,它会自动生成这个查询:stackoverflow.com/a/66115862/10646316

标签: c# linq entity-framework-core


【解决方案1】:

使用this code from my answer

然后用结果填充ExpandoObject:

var tablesinfo = Context.GetTablesInfo();
var expando = new ExpandoObject();
if (tablesinfo != null)
{
   var dic = (IDictionary<string, object>)expando;
   foreach(var info in tablesinfo)
   {
       dic.Add(info.TableName, info.RecordCount);
   }
}

想法是,如果您按常量对实体进行分组,则可以进行 UNION 计数。 示意函数构建以下 IQueryable 表达式:

var tablesinfo =
   Context.AppUsers.GroupBy(x => 1).Select(g => new TableInfo{ TableName = "asp_net_roles", RecordCount = g.Count() })
   .Concat(Context.MenuCategories.GroupBy(x => 1).Select(g => new TableInfo{ TableName = "menu_categories", RecordCount = g.Count() }))
   .Concat(Context.Items.GroupBy(x => 1).Select(g => new TableInfo{ TableName = "items", RecordCount = g.Count() }))
   ....

【讨论】:

    【解决方案2】:

    您的 LINQ 查询没有问题。这是非常可接受的方法。然而这并不是最有效的。

    无需从单个表中一一获取计数。您可以使用系统表Sys.Objects 和Sys.Partitions 一次从所有表中获取计数。只需尝试在您的数据库中运行此查询。

    SELECT A.Name AS TableName, SUM(B.rows) AS RecordCount  
    FROM sys.objects A INNER JOIN sys.partitions B 
    ON A.object_id = B.object_id  
    WHERE A.type = 'U' AND B.index_id IN (0, 1)
    GROUP BY A.Name
    

    为了快速响应和更简洁的代码,您可以将此 SQL 查询存储在字符串变量中,然后运行 ​​LINQ

    var result = dataContext.ExecuteQuery<YOUR_MODEL_CLASS>
                 (your_string_query);
    

    【讨论】:

    • 你想要AND B.index_id IN (0, 1) 否则你也会得到非聚集索引。您应该考虑使用比A 和B 更好的别名
    【解决方案3】:

    我会这样写:

    Dictionary<string, int> view = new() {
       new() {'asp_net_roles', Context.AppUsers.Count() },
       ...
    }
    return View(view);
    

    也许不是最纯粹的方式,但可以完成工作(除非我误解了你试图完成的工作)

    【讨论】:

    • 这类似于我目前的做法,并且存在为每个表生成sql请求的问题,例如50 个表,50 个请求。使用纯 SQL UNIONS 的示例只会生成 1 个 SQL 请求
    • 哦,我明白了......有UNION方法,但它适用于IEnumerables,而不是IQueryables
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-11-19
    • 1970-01-01
    • 2019-12-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多