【问题标题】:How to rotate data by converting rows to columns using LINQ如何通过使用 LINQ 将行转换为列来旋转数据
【发布时间】:2011-02-07 16:58:38
【问题描述】:

我编写了以下查询通过使用 LINQ 将行转换为列来旋转数据

var query = from p in context.PrivilegesTable
            group p by p.Type into g
            select new Privileges
            {
                Type = g.Key,
                AllowRead = g.Any(p => p.Seq == 1),
                AllowAdd = g.Any(p => p.Seq == 2)
                AllowEdit = g.Any(p => p.Seq == 3)
                AllowDelete = g.Any(p => p.Seq == 4)
            };

我认为有更好的方法来实现它。有关详细信息,请阅读以下内容:

我有以下权限表:

      Type    Seq
        1       1
        2       1
        2       2
        3       1
        3       2
        3       3

还有以下Privileges类:

class Privileges
{
   public int ID { get; set; }

   public Type Type { get; set;}

   public int AllowRead { get; set; } // when sequence = 1 
   public int AllowAdd { get; set; } // when sequence = 2
   public int AllowEdit { get; set; } // when sequence = 3
   public int AllowDelete { get; set; } // when sequence = 4
}

现在,我想使用 LINQ 创建一个List<Prvileges> 以获得以下结果:

[类型、AllowRead、AllowAdd、AllowEdit、AllowDelete]

[1,真,假,假,假]

[2、真、真、假、假]

[3、真、真、真、假]

我的查询对性能不利吗? 有更好的吗?

【问题讨论】:

    标签: c# linq linq-to-sql


    【解决方案1】:

    我建议使用enum 来表示您可以拥有的权限。

    [Flags]
    enum Privilege
    {
        None = 0,
        Read = 1,
        Add = 2,
        Edit = 4,
        Delete = 8,
    }
    

    通过这种方式,您可以存储一个值来表示您的所有权限。那么您的 Privileges 类将是这样的:

    class Privileges {
        public int ID { get; set; }
        public Type Type { get; set;}
        private Privilege m_Privileges;
    
        public bool AllowRead {
            get { return HasPrivilege(Privilege.Read); }
            set { CheckPrivilege(Privilege.Read, value); }
        }
    
        public bool AllowAdd {
            get { return HasPrivilege(Privilege.Add); }
            set { CheckPrivilege(Privilege.Add, value); }
        }
    
        public bool AllowEdit {
            get { return HasPrivilege(Privilege.Edit); }
            set { CheckPrivilege(Privilege.Edit, value); }
        }
    
        public bool AllowDelete {
            get { return HasPrivilege(Privilege.Delete); }
            set { CheckPrivilege(Privilege.Delete, value); }
        }
    
        private bool HasPrivilege(Privilege p) {
            return (m_Privileges & p) == p;
        }
    
        private void CheckPrivilege(Privilege p, bool owns) {
            if (owns)
                m_Privileges = m_Privileges | p;
            else
                m_Privileges = m_Privileges & (~p);
        }
    }
    

    当然,这种方法仅在您拥有有限且已知数量的权限时才有效。

    希望有帮助

    【讨论】:

    • 感谢解答,但是数据是存储的,我只想写最好的LINQ查询来读取。
    【解决方案2】:

    您的查询性能将很糟糕,因为每个 Any 都会进行连接(L2S 实施问题)。在 SQL 中,你会做一个 pivot 子句。它可以在 L2S 中模拟,但连接问题仍然存在(我今天在连接上报告了这个错误)。据我所知没有解决方法,抱歉。如果性能有问题,则必须缓存或使用原始 sql。

    编辑:我想我为你找到了一个特殊情况:

    var query = from p in context.PrivilegesTable
                let shift = 1 << p.Seq
                group shift by p.Type into g
                select new
                {
                    Type = g.Key,
                    AllowMask = g.Sum(),
                };
    

    这有多酷? ;-) 不幸的是,它的代码很糟糕,并且最多只能使用 64 位标志。

    【讨论】:

    • 你确定用 2 .Select() 避免多重连接是不可能的吗?
    猜你喜欢
    • 2019-12-05
    • 1970-01-01
    • 1970-01-01
    • 2011-11-12
    • 1970-01-01
    • 2021-10-27
    • 1970-01-01
    • 2018-02-25
    • 2019-09-27
    相关资源
    最近更新 更多