如何使用LINQ将行转换为列来旋转数据

时间:2011-02-07 16:58:38

标签: c# linq linq-to-sql

我使用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>,以获得以下结果:

[Type,AllowRead,AllowAdd,AllowEdit,AllowDelete]

[1,真,假,假,假]

[2,真,真,假,假]

[3,真,真,真,假]

我的查询对性能有害吗? 还有更好的吗?

2 个答案:

答案 0 :(得分:0)

我建议使用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);
    }
}

当然,只有拥有有限且已知数量的权限,此方法才有效。

希望有所帮助

答案 1 :(得分:0)

您的查询性能将非常糟糕,因为每个Any都会进行连接(L2S实现问题)。在SQL中你会做一个pivot子句。它可以在L2S中模拟但是连接问题仍然存在(我今天在连接上报告了这个错误)。对不起,我的知识没有解决方法。如果perf是个问题,则必须缓存或使用原始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位标志。