【问题标题】:Calculate Scope for a client by avoiding multiple entries通过避免多个条目来计算客户的范围
【发布时间】:2019-02-05 03:27:36
【问题描述】:

我有一个场景,角色和客户端存储在一个表中,我们必须在字典中获取它,并且必须确保对于一个用户,没有一个客户端有多个角色条目,并且如果它有最新的行版本记录。

在表格内,我们对用户、角色和客户端 ID 以及数据有唯一约束,如下所示:

#1- User,Role, Client Id, TimeStamp, rowVersion
    201,READ,101, 1/18/2019, 2
    201,WRITE,101, 1/18/2019, 1
    201,ADMIN,102, 1/18/2019, 3
    202,READ,102, 1/19/2019, 12

对于用户 201 - 客户端 101 只能有一个角色,以防有多个角色 - 排序后选择最新版本。 在上面的#1中,它将计算到下面并存储在字典中 -

201,READ,101, 1/18/2019, 2
201,ADMIN,102, 1/18/2019, 3

如何在查询数据并存储在字典中时使用 LINQ 有效地实现这一点?

编辑 实际上 RowVersion 是 SQL Server 行版本,例如 0x0000000000019E12 只是为了简化我添加了数字来显示。

我们需要记住,对于给定的用户,我们正在为此 RoleScope 进行计算。在我的示例结果中,用户 201 的方法是

201,READ,101, 1/18/2019, 2
201,ADMIN,102, 1/18/2019, 3

以我想在 LINQ 中转换的 SQL 形式回答

select * from(
select UserId,ClientId,RowVersion,RoleCode,row_number() 
over(partition by ClientId order by RowVersion desc) as roworder
from dbo.UR where UserId=6
) temp
where roworder=1

【问题讨论】:

  • 你尝试过任何 Linq qyery 吗?
  • 我只尝试了我在上述问题中更新的 SQL
  • 这里是工作解决方案的小提琴 = dotnetfiddle.net/ftQYij

标签: c# .net linq dictionary


【解决方案1】:

如果我明白你想要什么。并假设 rowversion 只是一个 int(而不是 SqlServer timeStamp

  1. 使用GroupBy
  2. OrderByrowVersion
  3. 选择Last(最高)
  4. ToDictionary

例子

var results = list.GroupBy(x => x.ClientId)
                  .Select(x => x.OrderBy(y => y.rowVersion).Last())
                  .ToDictionary(x => x.ClientId);

【讨论】:

  • 所以基本上我想按 ClientId 排序,然后按 Row Version 排序,然后为该用户 201 的每个角色选择顶部。 201,READ,101, 1/18/2019, 2 201,ADMIN,102, 1/18/2019, 3
  • 我做了一个小改动,选择了第一个而不是最后一个,因为想要最新的,
【解决方案2】:

具有以下类:

class ClientRole
{
    public int ClientId { get; set; }
    public string Role { get; set; }
    public int RowVersion { get; set; }
}

试试这个:

var clientRoles = new List<ClientRole>
{
    new ClientRole { ClientId = 101, Role = "READ", RowVersion = 2 },
    new ClientRole { ClientId = 101, Role = "WRITE", RowVersion = 1 },
    new ClientRole { ClientId = 102, Role = "ADMIN", RowVersion = 2 },
    new ClientRole { ClientId = 102, Role = "OTHER", RowVersion = 12 }
};

var clientRolesDic = (
    from cr in clientRoles
    group cr by cr.ClientId into g
    select g.OrderByDescending(i => i.RowVersion).First()
    )
    .ToDictionary(k => k.ClientId);

【讨论】:

  • 它缺少 UserId 部分,因为对于给定的用户,我们需要返回他的 RoleXClientId 映射。 201 用户有 201,READ,101, 1/18/2019, 2 201,ADMIN,102, 1/18/2019, 3
【解决方案3】:

似乎是一个简单的查询:

var clientRoles = new []
{
    new { ClientId = 101, Role = "READ", RowVersion = 2 },
    new { ClientId = 101, Role = "WRITE", RowVersion = 1 },
    new { ClientId = 102, Role = "ADMIN", RowVersion = 3 },
    new { ClientId = 102, Role = "READ", RowVersion = 2 },
};

var result =
    from cr in clientRoles
    orderby cr.ClientId, cr.RowVersion descending
    group cr by cr.ClientId into gs
    from g in gs.Take(1)
    select g;

这仅返回这些行:

    new { ClientId = 101, Role = "READ", RowVersion = 2 },
    new { ClientId = 102, Role = "ADMIN", RowVersion = 3 },

您的源数据中似乎有错误 - 最后一行应该有 2RowVersion,而不是 12

【讨论】:

  • 谢谢你让我试试这个,数据没有错误实际上是SQL Row版本,比如0x0000000000019E12
  • @DevG - 不用担心,但错误出现在问题中的示例数据中,否则您将无法获得示例输出 - 将返回 12 的行。
  • 如果您看到四行有两个用户 201 和 202。如果我在这种情况下查询用户 201,他的 RoleScope 将是 201,READ,101, 1/18/2019, 2 201, ADMIN,102, 1/18/2019, 3 在您的数据中您忘记了用户部分。还是我没有正确指定它?
  • 在问题中添加了明确的细节,如果让您感到困惑,我们深表歉意。
【解决方案4】:

如果 Fiddle Stop 在这里工作是完整的工作解决方案,包括上面 Randall 建议的。

using System;
using System.Linq;
public class Simple {
  public static void Main() {
            var userRoles = (new[] 
            { 
            new { clientid=1 , rowVersion = 1 , role="READ" },
            new { clientid=1 , rowVersion = 2 , role="EDIT" },
            new { clientid=2 , rowVersion = 3 , role="ADMIN" },
            new { clientid=1 , rowVersion = 4 , role="VIEW" }
        });

var o = userRoles.OrderByDescending(x => x.rowVersion)
                .GroupBy(x => x.clientid)
                .SelectMany(g =>
                   g.Select((j, i) => new { j.rowVersion, j.role, rn = i + 1 })
                   );

    var z =  o.Select(x => new {x.rowVersion, x.role, x.rn}).Where(a => a.rn==1);

      var results = userRoles.GroupBy(x => x.clientid)
                  .Select(x => x.OrderByDescending(y => y.rowVersion).First());

          Console.WriteLine("Solution #1");

        foreach (var i in z)
        {
            Console.WriteLine("{0} {1} {2}", i.rowVersion, i.role, i.rn);
        }

      Console.WriteLine("Solution #2");

      foreach (var k in results)
        {
            Console.WriteLine("{0} {1}", k.rowVersion, k.role);
        }

  }
  }

【讨论】:

  • 当我将它移植到代码中时,我遇到的唯一问题是“异常消息:无法比较数组中的两个元素”
猜你喜欢
  • 1970-01-01
  • 2016-02-12
  • 1970-01-01
  • 2018-11-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-20
  • 2019-01-02
  • 1970-01-01
相关资源
最近更新 更多