/// <summary>
        /// When overridden in a derived class, deletes all user-profile data for profiles in which the last activity date occurred before the specified date.
        /// </summary>
        /// <returns>The number of profiles deleted from the data source.</returns>
        /// <param name="authenticationOption">One of the <see cref="T:System.Web.Profile.ProfileAuthenticationOption" /> values, specifying 
        /// whether anonymous, authenticated, or both types of profiles are deleted.</param>
        /// <param name="userInactiveSinceDate">A <see cref="T:System.DateTime" /> that identifies which user profiles are considered 
        /// inactive. If the <see cref="P:System.Web.Profile.ProfileInfo.LastActivityDate" />  value of a user profile occurs on or before 
        /// this date and time, the profile is considered inactive.</param>
        public override int DeleteInactiveProfiles(ProfileAuthenticationOption authenticationOption, DateTime userInactiveSinceDate)
        {
            int num = 0;

            using (EFDataModelEntities context = new EFDataModelEntities(connectionString))
            {
                IQueryable<DataLayer.Profile> profiles = context.User.Where(MatchUserApplication())
                                                                     .Where(ApplyAuthenticationOption(authenticationOption))
                                                                     .Where(u => u.LastActivityDate <= userInactiveSinceDate.ToUniversalTime())
                                                                     .Select(u => u.Profile);

                foreach (DataLayer.Profile profile in profiles)
                {
                    context.DeleteObject(profile);
                    num++;
                }

                context.SaveChanges();
            }

            return num;
        }
        /// <summary>
        /// Adds the specified user names to the specified roles for the configured applicationName.
        /// </summary>
        /// <param name="userNames">A string array of user names to be added to the specified roles.</param>
        /// <param name="roleNames">A string array of the role names to add the specified user names to.</param>
        public override void AddUsersToRoles(string[] userNames, string[] roleNames)
        {
            using (EFDataModelEntities context = new EFDataModelEntities(connectionString))
            {
                IQueryable<Role> roles = context.Role.Where(MatchRoleApplication()).Where(ProviderUtils.BuildContainsExpression<Role, string>(r => r.Name, roleNames));
                if (roles.Count() != roleNames.Length)
                {
                    throw new ProviderException("Role not found.");
                }

                IQueryable<User> users = context.User.Where(MatchUserApplication()).Where(ProviderUtils.BuildContainsExpression<User, string>(u => u.Username, userNames));
                if (users.Count() != userNames.Length)
                {
                    throw new ProviderException("User not found.");
                }

                try
                {
                    foreach (User user in users)
                    {
                        foreach (Role role in roles)
                        {
                            // Check whether user is already in role
                            if (IsUserInRole(user.Username, role.Name))
                            {
                                throw new ProviderException(string.Format("User is already in role '{0}'.", role.Name));
                            }

                            user.Role.Add(role);
                        }
                    }

                    context.SaveChanges(false);
                }
                catch (Exception ex)
                {
                    if (WriteExceptionsToEventLog)
                    {
                        WriteToEventLog(ex, "AddUsersToRoles");
                    }
                    else
                    {
                        throw;
                    }
                }
                finally
                {
                    context.Connection.Close();
                }
            }
        }
        /// <summary>
        /// Removes the specified user names from the specified roles for the configured applicationName.
        /// </summary>
        /// <param name="userNames">A string array of user names to be removed from the specified roles.</param>
        /// <param name="roleNames">A string array of role names to remove the specified user names from.</param>
        public override void RemoveUsersFromRoles(string[] userNames, string[] roleNames)
        {
            using (EFDataModelEntities context = new EFDataModelEntities(connectionString))
            {
                IQueryable<Role> roles = context.Role.Where(MatchRoleApplication()).Where(ProviderUtils.BuildContainsExpression<Role, string>(r => r.Name, roleNames));
                if (roles.Count() != roleNames.Length)
                {
                    throw new ProviderException("Role not found.");
                }

                IQueryable<User> users = context.User.Include("Role").Where(MatchUserApplication()).Where(ProviderUtils.BuildContainsExpression<User, string>(u => u.Username, userNames));
                if (users.Count() != userNames.Length)
                {
                    throw new ProviderException("User not found.");
                }

                try
                {
                    foreach (User user in users)
                    {
                        foreach (Role role in roles)
                        {
                            /*if (!user.Role.IsLoaded)
                            {
                                user.Role.Load();
                            }*/

                            if (user.Role.Contains(role))
                            {
                                user.Role.Remove(role);
                            }
                        }
                    }

                    context.SaveChanges();
                }
                catch (Exception ex)
                {
                    if (WriteExceptionsToEventLog)
                    {
                        WriteToEventLog(ex, "RemoveUsersFromRoles");
                    }
                    else
                    {
                        throw;
                    }
                }
            }
        }
        /// <summary>
        /// Removes a role from the data source for the configured applicationName.
        /// </summary>
        /// <param name="roleName">The name of the role to delete.</param>
        /// <param name="throwOnPopulatedRole">If true, throw an exception if <paramref name="roleName"/> has one or more members and do not delete <paramref name="roleName"/>.</param>
        /// <returns>
        /// true if the role was successfully deleted; otherwise, false.
        /// </returns>
        public override bool DeleteRole(string roleName, bool throwOnPopulatedRole)
        {
            // Validate role
            if (!RoleExists(roleName))
            {
                throw new ProviderException("Role does not exist.");
            }

            if (throwOnPopulatedRole && GetUsersInRole(roleName).Length > 0)
            {
                throw new ProviderException("Cannot delete a populated role.");
            }

            using (EFDataModelEntities context = new EFDataModelEntities(connectionString))
            {
                Role role = GetRole(r => r.Name == roleName, context);
                if (role == null)
                {
                    return false;
                }

                try
                {
                    context.DeleteObject(role);
                    context.SaveChanges();
                }
                catch (Exception ex)
                {
                    if (WriteExceptionsToEventLog)
                    {
                        WriteToEventLog(ex, "DeleteRole");
                        return false;
                    }

                    throw;
                }

                return true;
            }
        }
        /// <summary>
        /// Adds a new role to the data source for the configured applicationName.
        /// </summary>
        /// <param name="roleName">The name of the role to create.</param>
        public override void CreateRole(string roleName)
        {
            // Validate role name
            if (roleName.Contains(","))
            {
                throw new ArgumentException("Role names cannot contain commas.");
            }

            if (RoleExists(roleName))
            {
                throw new ProviderException("Role name already exists.");
            }

            try
            {
                using (EFDataModelEntities context = new EFDataModelEntities(connectionString))
                {
                    Application application = ProviderUtils.EnsureApplication(ApplicationName, context);

                    // Create new role
                    Role newRole = new Role
                                       {
                                           Id = Guid.NewGuid(),
                                           Name = roleName,
                                           Application = application
                                       };
                    context.AddToRole(newRole);
                    context.SaveChanges();
                }
            }
            catch (Exception ex)
            {
                if (WriteExceptionsToEventLog)
                {
                    WriteToEventLog(ex, "CreateRole");
                }
                else
                {
                    throw;
                }
            }
        }
        /// <summary>
        /// Gets the property values from database.
        /// </summary>
        /// <param name="userName">Name of the user.</param>
        /// <param name="propertiesValues">The property values.</param>
        private void ExtractPropertyValuesFromDatabase(string userName, SettingsPropertyValueCollection propertiesValues)
        {
            string[] propertyNames = null;
            string propertiesValuesSerialized = null;
            byte[] propertiesValuesBinary = null;

            using (EFDataModelEntities context = new EFDataModelEntities(connectionString))
            {
                User user = context.User.Include("Profile").Where(MatchUserApplication()).Where(u => u.Username == userName && u.Profile != null).FirstOrDefault();
                if (user != null)
                {
                    propertyNames = user.Profile.PropertyNames.Split(new[] { ':' });
                    propertiesValuesSerialized = user.Profile.PropertyValuesString;
                    propertiesValuesBinary = user.Profile.PropertyValuesBinary;

                    // Update user
                    user.LastActivityDate = DateTime.Now;
                    context.SaveChanges();
                }
            }

            ParseDataFromDatabase(propertyNames, propertiesValuesSerialized, propertiesValuesBinary, propertiesValues);
        }
        /// <summary>
        /// Sets the values of the specified group of property settings.
        /// </summary>
        /// <param name="context">A <see cref="T:System.Configuration.SettingsContext" /> describing the current application usage.</param>
        /// <param name="properties">A <see cref="T:System.Configuration.SettingsPropertyValueCollection" /> representing the group 
        /// of property settings to set.</param>
        public override void SetPropertyValues(SettingsContext context, SettingsPropertyValueCollection properties)
        {
            string username = (string)context["UserName"];

            if (string.IsNullOrEmpty(username) || properties.Count < 1)
            {
                return;
            }

            bool userIsAuthenticated = (bool)context["IsAuthenticated"];
            string propertiesNames = string.Empty;
            string propertiesValuesSerialized = string.Empty;
            byte[] propertiesValuesBinary = null;

            PrepareDataForSaving(ref propertiesNames, ref propertiesValuesSerialized, ref propertiesValuesBinary, properties, userIsAuthenticated);

            if (propertiesNames.Length != 0)
            {
                using (EFDataModelEntities dataContext = new EFDataModelEntities(connectionString))
                {
                    // Attempt to load user with associated profile
                    User user = dataContext.User.Include("Profile").Where(MatchUserApplication()).Where(u => u.Username == username).FirstOrDefault();

                    if (user == null)
                    {
                        throw new ArgumentException("user");
                    }

                    if (user.Profile == null)
                    {
                        // Create new profile
                        user.Profile = new DataLayer.Profile();
                    }

                    // Set profile values
                    user.Profile.PropertyNames = propertiesNames;
                    user.Profile.PropertyValuesString = propertiesValuesSerialized;
                    user.Profile.PropertyValuesBinary = propertiesValuesBinary;
                    user.Profile.LastUpdatedDate = DateTime.Now;
                    dataContext.SaveChanges();
                }
            }
        }
        /// <summary>
        /// When overridden in a derived class, deletes profile properties and information for profiles that match the supplied list of user names.
        /// </summary>
        /// <returns>The number of profiles deleted from the data source.</returns>
        /// <param name="usernames">A string array of user names for profiles to be deleted.</param>
        public override int DeleteProfiles(string[] usernames)
        {
            int num = 0;

            using (EFDataModelEntities context = new EFDataModelEntities(connectionString))
            {
                IQueryable<User> users = context.User.Include("Profile").Where(u => usernames.Contains(u.Username) && u.Profile != null);

                foreach (User user in users)
                {
                    context.DeleteObject(user.Profile);
                    num++;
                }

                context.SaveChanges();
            }

            return num;
        }