简体   繁体   中英

Group by in linq + select

say I have this data

1   757f27a2-e997-44f8-b2c2-6c0fd6ee2c2f    2   3
2   757f27a2-e997-44f8-b2c2-6c0fd6ee2c2f    3   1
3   757f27a2-e997-44f8-b2c2-6c0fd6ee2c2f    2   2

column 1 // pk
column 2 // userId
column 3 // courseId
column 4 // permissionId

I have this class

class CoursePermissions
    {
        public string Prefix { get; set; }
        public bool OwnerPermission { get; set; } // permissionId 1
        public bool AddPermission { get; set; } // permissionId 2
        public bool EditPermission { get; set; } // permissionId 3
    }

I want to group all the 3 rows by courseId(or Prefix) and then take that information and make a class out Of it

So the end result would be

List<CoursePermissions> permissions = new List<CoursePermissions>();

CoursePermissions a = new CoursePermissions
{
   Prefix = "comp101";
   OwnerPermission = false,
   AddPermission  = true,
   EditPermission = true
};


CoursePermissions b = new CoursePermissions
{
   Prefix = "comp102";
   OwnerPermission = true,
   AddPermission  = false,
   EditPermission = false 
};

permissions.Add(a);
permissions.Add(b);

So the above is how the object would look if I took all the row data from the db and manually made it the way I wanted it too look. Of course I need to do it somehow as a query.

In my example I have 2 students. They both belong to the same course. Student 1has edit and Add permission for Comp101 but only owner permissions for comp102.

I want to get all the rows back for Comp101 and put it into CoursePermissions. Then I want to get all the rows back for Comp102 and put it into CoursePermissions. Then store all these in a collection and use them.

The only thing I can do is something like this

 var list = session.Query<PermissionLevel>().Where(u => u.Student.StudentId == studentId).ToList();

            IEnumerable<IGrouping<string, PermissionLevel>> test = list.GroupBy(x => x.Course.Prefix);

            foreach (var t in test)
            {
                CoursePermissions c = new CoursePermissions();

                foreach (var permissionLevel in t)
                {
                    if (permissionLevel.PermissionLevelId == 1)
                    {
                        c.OwnerPermission = true;
                    }
                }
            }

It would nice if I could get rid of the nest for each loop and do it all when the data comes from the query.

Here's an approach that I think is quite functional.

First set up a dictionary of actions that will set the appropriate course permission given a permission level id.

var setPermission = new Dictionary<int, Action<CoursePermissions>>()
{
    { 1, cps => cps.OwnerPermission = true },
    { 2, cps => cps.AddPermission = true },
    { 3, cps => cps.EditPermission = true },
};

Now create a function that will turn the course prefix and a list of permission level ids into a new CoursePermissions object.

Func<string, IEnumerable<int>, CoursePermissions>
    buildCoursePermission = (prefix, permissionLevelIds) =>
    {
        var cps = new CoursePermissions() { Prefix = prefix };
        foreach (var permissionLevelId in permissionLevelIds)
        {
            setPermission[permissionLevelId](cps);
        }
        return cps;
    };

Now all you have left is a simple query that turns your list of permission levels into a list of course permissions.

var coursePermissionsList =
    (from pl in list
     group pl.PermissionLevelId by pl.Course.Prefix into gcpls
     select buildCoursePermission(gcpls.Key, gcpls)).ToList();

How does that work for you?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM