Click here to Skip to main content
15,891,136 members
Please Sign up or sign in to vote.
1.00/5 (1 vote)
I am working on a server side processing datatable which gets about 1000 fake/generic users data from the database and loads 10 rows per page. The way I have written my code right now, it takes at least 2 minutes just to show the first 10 rows.

I have debugged it to find the reason it is taking so long is because I am getting the Roles for each user and showing it on the datatable. When I comment out the getting the roles part and use an empty string and List, the datatable loads fast. But I have to get the Roles and I having a hard time to figure out how to do it. Can someone please help me out in this matter? I have been struggling with the SQL part for the longest time and no success so far.

What I have tried:

private async Task<IEnumerable<UserViewModel>> GetUserData(ApplicationDbContext db)
{
    var users = db.Users;
    var list = await GetUsers(db, users);
    var vmlist = list.Select(item => new UserViewModel()
    {
        ID = item.ID,
        Username = item.Username,
        FirstName = item.FirstName,
        LastName = item.LastName,
        Email = item.Email,
        TaxID = item.TaxID,
        TaxIdHash = item.TaxIdHash,
        IV = item.IV,
        TaxIDEncrypted = item.TaxIDEncrypted,
        //RoleList = new List<string>(),
        //Roles = "",

        // This is the part giving me issues
        RoleList = RoleRepository.GetRolesByUserId(UserManager, item.ID, false),
        Roles = string.Join(",", RoleRepository.GetRolesByUserId(UserManager, item.ID, false).ToArray()),
    });

    return vmlist;
 }


I am calling the GetUserData method in this UserGrid method.

public async Task<ActionResult> UserGrid(DataTablesViewModel param)
{
    using (var db = new Infrastructure.Data.ApplicationDbContext())
    {
        db.Database.Log = s => System.Diagnostics.Debug.WriteLine(s);

    var data = await GetUserData(db);

    IQueryable<UserViewModel> filteredUsers = data.AsQueryable();        

    List<UserViewModel> displayedTasks = filteredUsers.Skip(param.iDisplayStart).Take(param.iDisplayLength).ToList();

    int count = filteredUsers.Count();
    foreach (var item in displayedTasks){
        if (!String.IsNullOrEmpty(item.TaxID) && item.IV != null && item.TaxIDEncrypted != null)
        {
            if (item.RoleList.Any(x => x == UserRoles.Applicant))
            {
                string ssndecrypt = GenericHelper.DecryptPortalTaxID(item.IV, item.TaxIDEncrypted);
                string ssn = (ssndecrypt.Length == 11 ? ssndecrypt.Substring(7, 4) : ssndecrypt);
                item.TaxID = (ssndecrypt.Length == 11 ? String.Join("", item.TaxID.Substring(0, 7), ssn) : ssn);}
        }
        else
        {
            item.TaxID = String.Empty;
        }
        item.Delete = item.RoleList.Intersect(UserRoles.CanDelete).Count() > 0 ?
            "<a class=\"delete\"  data-url=\"" + Url.Action("DeleteUser", "Users") + "\" data-userid=\"" + item.ID + "\"data-username=\"" + item.Username + "\" href=\"#\">Delete User</a>"
            : String.Empty;
    }

    var result = GridHelper.GetData(displayedTasks);
    var json = Json(new
    {
        sEcho = param.sEcho,
        iTotalRecords = count,
        iTotalDisplayRecords = count,
        aaData = result
    },
JsonRequestBehavior.AllowGet);
    return await Task.FromResult(json);
}


I will need the RoleList because I use it later for decrypting the encrypted SSN and showing its last 4 numbers.

This is the UserViewModel if needed.

public UserViewModel(IList<string> roles, ApplicationUser user)
        {
            ID = user.Id;
            Username = user.UserName;
            Email = user.Email;
            RoleList = roles.ToList(); ;
            Roles = string.Join(",", RoleList.ToArray());
            IsActive = user.IsActive;

            AllowRoleChanges = !RoleList.Intersect(UserRoles.FinalConsumers).Any();
            AssignableRoles = HousingServices.Core.Models.UserRoles.CanCreate.Select(x => new SelectListItem { Text = x, Value = x }).ToList();
            if (RoleList.Contains(UserRoles.Caseworker))
            {
                AssignableRoles.Add(new SelectListItem { Value = UserRoles.Caseworker, Text = UserRoles.Caseworker });
            }
            RoleIDs = RoleList.Select(x => x).ToList();
          ..........

        }
        
    }


private async Task<IEnumerable<dynamic>> GetUsers(ApplicationDbContext db, IDbSet<ApplicationUser> users)
        {
            IQueryable<ApplicationUser> userlist = users;
          <pre>var hsuserlist = userlist.Join(db.EliteHousingServicesUsers, u => u.Id, hu => hu.UserId, (u, hu) => new
            {
                ID = u.Id,
                Username = u.UserName,
                FirstName = hu.FirstName,
                LastName = hu.LastName,
                Email = u.Email,
                TaxID = "XXX-XX-XXXX",
                Active = (u.IsActive ? "Yes" : "No"),
                TaxIdHash = hu.TaxIDHash,
                IV = hu.IV,
                TaxIDEncrypted = hu.TaxIDEncrypted,
                IsActive = u.IsActive,
                Status = (u.AccessFailedCount >= MaxFailedAccessAttemptsBeforeLockout ?
                "<a class=\"unlock\" data-url=\"" + unlockUrl + "\" data-userid=\"" + u.Id + "\"data-username=\"" + u.UserName + "\" href=\"#\">Unlock</a>"
                : "<a class=\"reset\" data-url=\"" + resetUrl + "\" data-userid=\"" + u.Id + "\"data-username=\"" + u.UserName + "\" href=\"#\">Reset Password</a>"),
            });
Posted
Updated 27-Apr-17 4:43am
v3

1 solution

Well, I don't know what the Roles have to do with your code, but you can save a ton of time by restructuring your database a bit. The SSN has to be decrypted to get the last 4 digits, the least secure part of the string. So, don't decrypt it. Store the last 4 as a separate column and retrieve that instead of the full SSN. You get to skip the entire decrypt operation, saving yourself a ton of time.
 
Share this answer
 
Comments
[no name] 26-Apr-17 22:52pm    
I cannot do that with the SSN. The SSNs are hashed in the database. I am trying to just get the Roles for each user. Cannot change anything with the SSN part.
PIEBALDconsult 26-Apr-17 23:05pm    
If you're a developer you can do anything.
[no name] 26-Apr-17 23:08pm    
I meant I cannot modify that part of the project. And I am not a "Dev" as per say... just an intern.
Dave Kreskowiak 26-Apr-17 23:44pm    
OK, so then comment out those three lines of code that decrypt the SSN and put dummy data, just a simple string, into item.TaxID. You're intentionally skipping the decryption phase for a performance test.

Run the code. If the datatable comes back fast now, you know where the problem is and you just said you can't do anything about it.
[no name] 27-Apr-17 8:57am    
The problem of it running slow is not in the decrypting part. It is in the getting the roles for each user part.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900