【问题标题】:Query in asp.net core在 asp.net core 中查询
【发布时间】:2021-06-13 00:08:07
【问题描述】:

我有一个这样的查询表,人们让我问当我得到用户ID来查询Document表时,如何获取当前用户的Positions数据。

var claimsIdentity = _httpContextAccessor.HttpContext.User.Identity as ClaimsIdentity;
        var userId = claimsIdentity.FindFirst(ClaimTypes.NameIdentifier)?.Value.ToString();
        var query = from c in _context.Documents
                    join u in _context.Users on c.UserID equals u.Id
                    join p in _context.Positions on u.Id equals p.UserID
                    where c.UserID.ToString() == userId
                    select new { c, u, p };

【问题讨论】:

  • 如果目的只是获取当前用户的Positions数据并且没有与Documents相关的过滤器,这里应该只涉及2个表:User & Position .因此,您无需在此查询中加入Documents,这可能会产生Position 的重复信息,并使得提取最终的Positions 集变得更加困难。删除_context.Documents,最终查询将返回所有Positions,每个User都与相应的User配对。那应该是您想要的数据。
  • 我想通过用户当前查询2表文档和位置
  • 我刚刚添加了一个答案来帮助您。我希望这就是你想要的。如果没有,请留下您的评论以使其更清楚。同样,对于此类问题,您得到答案的机会比其他类型的问题高得多。因为它只是与查询相关,而且许多用户喜欢 LINQ。但是你应该更清楚要求,尤其是你想要的数据格式。

标签: mysql linq asp.net-core entity-framework-core


【解决方案1】:

你查询的数据差不多够了,但是里面包含DocumentPosition的重复条目。如果您希望将最终查询放在这样的单个对象中:

{
    User = ...,
    Documents = ...,
    Positions = ...
}

您只需要使用 Linq-to-object 进行投影(因为所有数据都已加载并准备好在客户端进行投影):

var result = (from document in _context.Documents
             join user in _context.Users on document.UserID equals user.Id
             join position in _context.Positions on user.Id equals position.UserID
             where document.UserID.ToString() == userId
             select new { document, user, position }).AsEnumerable()
             .GroupBy(e => e.user.Id)
             .Select(g => new {
                 User = g.First().user,
                 Documents = g.GroupBy(e => e.document.Id)
                              .Select(e => e.First().document),
                 Positions = g.GroupBy(e => e.position.Id)
                              .Select(e => e.First().position)
             }).FirstOrDefault();

如果您不想获取用户信息,则无需加入该 DbSet,而是直接加入两个 DocumentPosition,如下所示:

var result = (from document in _context.Documents
              join position in _context.Positions on document.UserID equals position.UserID
             where document.UserID.ToString() == userId
             select new { document, position }).AsEnumerable()
             .GroupBy(e => e.document.UserID)
             .Select(g => new {
                 Documents = g.GroupBy(e => e.document.Id)
                              .Select(e => e.First().document),
                 Positions = g.GroupBy(e => e.position.Id)
                              .Select(e => e.First().position)
             }).FirstOrDefault();

请注意,我认为您的DocumentPosition 都有自己的主键属性Id(根据您的实际设计进行调整)。 最后,通常如果您的User 实体类型将导航集合属性 暴露给DocumentPosition。我们可以有一个更好(但相等)的查询,如下所示:

var user = _context.Users
                   .Include(e => e.Documents)
                   .Include(e => e.Positions)
                   .FirstOrDefault(e => e.Id.ToString() == userId);

这要简单得多,因为所有连接都由 EFCore 内部翻译。 导航集合属性的设计中嵌入了魔力。

我想谈谈条件UserID.ToString() == userIdId.ToString() == userId 的重要说明。您应该避免这种情况,因为它会被翻译成一个查询,从而破坏使用索引进行过滤。而是先尝试解析int userId(在您的情况下看起来像是一个字符串),然后直接使用解析后的int 在查询中进行比较,如下所示:

if(!int.TryParse(userId, out var intUserId)){
    //return or throw exception
}
                           
//here we have an user id of int, use it directly in your query
var user = _context.Users
                   .Include(e => e.Documents)
                   .Include(e => e.Positions)
                   .FirstOrDefault(e => e.Id == intUserId);

这同样适用于其他查询。

【讨论】:

    猜你喜欢
    • 2022-07-23
    • 1970-01-01
    • 2019-03-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-18
    • 2020-08-14
    相关资源
    最近更新 更多