4

I am tying to deactivate the user automatically once the expiry date is over. So while viewing the user account details, the account of the users who crossed Expiry Date should be shown as inactive (Using fa-toggle on/off - to show active/inactive status of account - in code it is a bool value true/false).

Existing:

  1. While clicking on get account details,
  2. Details will be extracted from DB displayed,
  3. As extracted it will be displayed in the application

What I did is ?

  1. While clicking on get account details,
  2. Details will be extracted from DB displayed,
  3. Before displaying to the end user,
  4. I am trying to change the active/inactive details of the customer, by comparing current date with expiry date.
  5. As extracted it will be displayed in the application

Existing Code:

public IEnumerable<CustomerDetails> GetCustomerDetails(string groupName)
{
    IEnumerable<CustomerDetails> customers;

    var query = "select up.username, up.firstname, up.lastname, up.lastactivitydate, up.expirydate, " +
                            "up.activationdate, up.licensedby, up.position, up.isactive as isActiveUser, " +
                            "wr.rolename, up.usergroup, ul.contracttype as contracttype, ul.numberoflicense as " +
                            "licensesallowed from userprofile up inner join userlicense ul on ul.id = up.firmid inner join " +
                            "webpages_UsersInRoles wur on wur.userid =  up.userid inner join webpages_Roles wr on " +
                            "wr.roleid = wur.roleid where ul.firmname='" + firmname.Replace("'", "''") + "' order by up.lastname";

    using (IDbConnection dbConnection = new SqlConnection(UserDBConnectionString))
    {
        dbConnection.Open();

        using (var result = dbConnection.QueryMultiple(query, commandTimeout: 300))
        {
            var accounts = result.Read().ToList();

            customers = from account in accounts
                                         select new CustomerDetails
                                         {
                                             FirstName = account.firstname,
                                             LastName = account.lastname,
                                             UserName = account.username,
                                             PreviousUserName = account.username,
                                             Position = account.position,

                                             SharedSpace = JsonConvert.DeserializeObject<string[]>(account.usergroup),

                                             UserRole = account.rolename,
                                             IsActiveUser = account.isActiveUser,

                                             LastActivityDate = account.lastactivitydate != null
                                             ? account.lastactivitydate.ToString("yyyy/MM/dd")
                                             : "",

                                             ExpiryDate = TimeZoneInfo.ConvertTimeToUtc((DateTime)account.expirydate),

                                             ActivationDate = TimeZoneInfo.ConvertTimeToUtc((DateTime)account.activationdate),

                                             ContractType = account.contracttype.ToString().Trim(),

                                             LicensesAllowed = account.licensesallowed
                                         };
        }
    }
    return customers;
}

The thing I did is before returning customers details, return customers;. I have included the following set of code to deactivate the users who all crossed the activation period. But it is not working as expected.

// code as above shown
var count = customers.Count();
for (var i = 0; i < count;i++)
{
    DateTime dateLimit = Convert.ToDateTime(customers.ElementAt(i).ExpiryDate); 
    DateTime currentDate = DateTime.Now.Date;
    int result = DateTime.Compare(dateLimit,currentDate);
    if (result == -1)
    {
        if (customers.ElementAt(i).IsActiveUser == true)
        {
            var beforeChanged = customers.ElementAt(i).IsActiveUser; // before it is true

            customers.ElementAt(i).IsActiveUser = false; // i hope i am setting the value as false

            var afterChanged = customers.ElementAt(i).IsActiveUser; // but i am still seeing true only here               

        }                    
    }
}
return customers
}

Edit -1 :

enter image description here

As I said in comment, I can able to change the value here from true to false vice versa.

Edit -2 :

// customer class structure

public class CustomerDetails
{
    public string FirstName { get; set; }

    public string LastName { get; set; }

    public bool IsActiveUser { get; set; }
    // some other fields ... goes here
}

I don't know how it still be true after setting the value as false.

Nakilon
  • 34,866
  • 14
  • 107
  • 142
Jeya Suriya Muthumari
  • 1,947
  • 3
  • 25
  • 47
  • Can you show us the CustomerDetails class? – Domysee Mar 24 '16 at 07:38
  • 5
    Maybe it is because of `delayed execution`? Your `customers` seem to be of `IEnumerable` type. Another possibility is that, since the `IsActiveUser` is a `property` - its `setter` may not allow you to set the value as `false` for some internal reason... – Ian Mar 24 '16 at 07:38
  • 1
    Try changing `return customers;` to `return customers.ToArray();` and see if the issue goes away. – Enigmativity Mar 24 '16 at 07:45
  • As @Ian said, the problem is delayed execution, you are effectively enumerating the query two times, each time giving you a new list of new `CustomerDetails`s. So when the UI is displaying the list, it does not show the changes you've made to the first list. – Alireza Mar 24 '16 at 07:46
  • In general, don't *store* data in your database that can be computed from existing data. If an inactive user is defined as one with an expiry date in the past, why do you need to *store* `IsActiveUser`? – Damien_The_Unbeliever Mar 24 '16 at 07:48
  • But I can change the value to `false` by seeing the values of the customers by placing the mouse over the variable while debugging in visual studio. Is this possible in `delayed execution` ? – Jeya Suriya Muthumari Mar 24 '16 at 08:39
  • Please see ["Should questions include “tags” in their titles?"](http://meta.stackexchange.com/questions/19190/should-questions-include-tags-in-their-titles), where the consensus is "no, they should not"! –  Mar 24 '16 at 08:46

2 Answers2

8

You are a victim of deferred execution.

Here, you query your database three times, every time you call customers.

var beforeChanged = customers.ElementAt(i).IsActiveUser; 

customers.ElementAt(i).IsActiveUser = false;

var afterChanged = customers.ElementAt(i).IsActiveUser;

Every time, you load the object from the database, which is why you see no changes. The database is unchanged.

You need to materialize your query, maybe by calling .ToArray() or ToList() on customers when you build your select.

Community
  • 1
  • 1
nvoigt
  • 75,013
  • 26
  • 93
  • 142
2

Problem: customers is an IEnumerable/IQueryable, and not a fixed list. It is a "definition of how to deliver objects", and not a list of actual or stable objects. Every reference to an 'element' causes customers to consult its source (the List<>), and to create whole brand new objects as you are retrieving them. Every... single... time.

Solution: Make sure that customers is created using a persisting function such as ToArrray() or ToList().

Peter B
  • 22,460
  • 5
  • 32
  • 69